- 能使用二分搜索的前提是数组已排序。
- 二分查找的使用场景:(1)可转换为find the first/last position of...(2)时间复杂度至少为O(lgn)。
- 递归和迭代的使用场景:能用迭代就用迭代,特别复杂时采用递归。
Ref:https://algorithm.yuanbin.me/zh-hans/binary_search/binary_search.md
leetcode 374
We are playing the Guess Game. The game is as follows:
I pick a number from 1 to n. You have to guess which number I picked.
Every time you guess wrong, I'll tell you whether the number is higher or lower.
You call a pre-defined API guess(int num) which returns 3 possible results (-1, 1, or 0):
-1 : My number is lower
1 : My number is higher
0 : Congrats! You got it!
Example:
n = 10, I pick 6.
Return 6.
public int guessNumber(int n) {
int start = 1;
int end = n;
int mid;
int tmp;
while(start < end){
mid = start/2 + end/2;
tmp = guess(mid);
if ( tmp == 0) return mid;
else if ( tmp == 1){
start = mid + 1;
} else{
end = mid - 1;
}
}
return start;
}
在上述程序中
mid = start/2 + end/2;
这里之所以这样写是防止两数相加后溢出。
while(start < end)
循环判断不取等号可以防止死循环。
当涉及数组时,我们经常会发生数组越界的情况,这种时候我们可以采取补项的思路。
定义 lower bound 为在给定升序数组中大于等于目标值的最小索引,upper bound 则为小于等于目标值的最大索引.以lower bound为例:
public static int lowerBound(int[] nums, int target) {
if (nums == null || nums.length == 0) return -1;
int lb = -1, ub = nums.length;
while (lb + 1 < ub) {
int mid = lb + (ub - lb) / 2;
if (nums[mid] < target) {
lb = mid;
} else {
ub = mid;
}
}
return lb + 1;
}
这里我们采取,使lb,ub在数组边界的两端+1,而不是刚好等于数组边界。
int lb = -1, ub = nums.length;
如果遇到有问插入索引的位置时,可以分三种典型情况:
1.目标值在数组范围之内,最后返回值一定是 lb + 1
2.目标值比数组最小值还小,此时 lb 一直为 -1 , 故最后返回 lb + 1 也没错,也可以将 -1 理解为数组前一个更小的值
3.目标值大于等于数组最后一个值,由于循环退出条件为 lb + 1 == ub , 那么循环退出时一定有 lb = A.length - 1 , 应该返回 lb + 1