目录
步骤
额外注意
时间复杂度——O(logn)
空间复杂度——O(1)
1.严格有序数组查找==target的数字,没有返回-1
2.有序数组查找刚好>=target的数字,没有返回-1
3.有序数组查找刚好<=target的数字,没有返回-1
不需要死记硬背,灵活理解使用。
前提条件是数组满足二段性(有序性包涵在二段性内),前面一段满足某个性质,后面一段满足另一个性质。通常遇见的都是有序性。
举个例子:假如我们的目标是找到有序数组中第一个<=target的数字。在if(nums[mid] <= target),分支中,我们来确定l = mid, 还是l = mid + 1.答案是l = mid .
因为此时的mid 是可能属于我们的目标的,因为if分支就是小于等于,所以根据上述第4点想法,此时l = mid.那么 mid 的更新就应该是mid = (l + r + 1) >>1, 保证不陷入死循环。
同理, 我们来判断另一个if分支if(nums[mid] > target)中,r = mid , 还是 r = mid - 1。答案是r = mid - 1.
因为在这个if分支中是大于,不是我们想找到的小于等于,所以此时mid 不是我们的目标,那么需要进行-1,也就是r = mid - 1.
其他的情况也是类似推导即可,只需要理解。
mid的更新还可以是以下两种写法
int mid = l + (r - l ) / 2.这个主要是为了防止(l + r)越界。(或者直接用long 定义mid)
int mid = (l + r) / 2;移位的计算会比直接除法更快,所以通常用移位。
// 找到等于target
public int getIndex(Listlist, int target){
int n = list.size();
if(n == 0) return -1;
int l = 0, r = n - 1;
while(l < r){
int mid = (l + r) >> 1;
if(lis.get(mid) == target)
return target;
else if(list.get(mid) < target)
l = mid + 1;
else
r = mid - 1;
}
if(l < n && list.get(l) == target) return list.get(l);
else return -1;
}
// 找到第一个大于等于target
public int getIndex1(Listlist, int target){
int n = list.size();
if(n == 0) return -1;
int l = 0, r = n - 1;
while(l < r){
int mid = (l + r) >> 1;
if(list.get(mid) < target)
l = mid + 1;
else
r = mid;
}
if(l < n && list.get(l) >= target) return list.get(l);
else return -1;
}
// 找到小于等于target
public int getIndex2(Listlist, int target){
int n = list.size();
if(n == 0) return -1;
int l = 0, r = n - 1;
while(l < r){
int mid = (l + r + 1) >> 1;
if(list.get(mid) <= target)
l = mid;
else
r = mid - 1;
}
if(l < n && list.get(l) <= target) return list.get(l);
else return -1;
}