二分查找要求数据有二段性,可以将查找某个分割点的时间复杂度从O(N)加速至O(logN)
LC704. 二分查找 {#LC704-二分查找}
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target
写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
示例1:
输入: nums = [-1,0,3,5,9,12], target = 9 输出:4
解释:9出现在 nums中并且下标为4
示例2:
输入:nums = [-1,0,3,5,9,12],target = 2 输出:-1
解释:2不存在nums中因此返回-1
思路:
二分查找->梦开始的地方
这道题是二分查找的入门题目,二分查找的水非常深,但是简单的题目通常会由于各种原因丢分。
这里我总结一下二分查找的一些模板和做题套路
首先能用二分查找的前提 是在可以根据f(mid)的值来判断下一个合法区间在mid左边还是右边
因此二分查找前面通常都会有排序等步骤来确保问题具有**"二段性"**
总体要注意的:
1.while (l < r): 这种写法使得退出条件是l==r,因此执行完之后必定有l==r
2.mid的求法: 这个mid的求法非常讲究,我总结的是
- mid = l + (r - l + 1) / 2,mid主动偏右->右边界主动收缩r = mid - 1;
- mid = l + (r - l ) / 2,mid主动偏左->左边界主动收缩l = mid + 1;
3.下一个区间的判断采用减治思想,将一定不符合条件的先排除,如:nums[mid] > target,那么mid必定不符合题意!->r = mid - 1
然后另外一个区间是其反面,一般是将合法区间包含在边界,如:nums[mid] <=target,那么mid可能不符合题意!->l = mid
4.退出循环的时候要重复利用好l==r这个条件,答案蕴藏在其中!
|---------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| class Solution { public int search(int[] nums, int target) { /* 在升序数组中查找目标数字对应下标->二分查找 */ int l = 0, r = nums.length - 1; while (l < r) { // 下面是右边主动收缩 int mid = l + (r - l + 1) / 2; // >target,说明target在左边(不含) if (nums[mid] > target) { r = mid - 1; } else { // <=target,说明target在右边(含) l = mid; } } // l==r,nums[l]要不就是target;要不就是nums中没有target return nums[l] == target ? l : -1; } }
|