目录
步骤
额外注意
时间复杂度——O(logn)
空间复杂度——O(1)
1.严格有序数组查找==target的数字,没有返回-1
2.有序数组查找刚好>=target的数字,没有返回-1
3.有序数组查找刚好<=target的数字,没有返回-1
不需要死记硬背,灵活理解使用。
步骤
前提条件是数组满足二段性(有序性包涵在二段性内),前面一段满足某个性质,后面一段满足另一个性质。通常遇见的都是有序性。
- 注意判断一开始的边界条件, 比如n == 0.
- 定义的时候,只需要记住一种模版就行,就是l = 0, r = n - 1, while(l < r), return l
- mid 有两种情况,一种是(l + r) >> 1 或者是 (l + r + 1)>> 1。mid 是否+ 1主要看 l 是否有+1的操作, 如果l = mid, 那么mid = (l + r + 1) >> 1; 如果l = mid + 1, 那么mid = (l + r) >> 1
- l 是否+1 或者 r 是否需要 -1,其实道理是一样的。因为while循环中最后返回的时候一定有l == r, 而我们所需要的答案就是l或者r, 所以我们需要判断l 或者r 是否是我们可能的目标,如果可能是我们最终的答案,那么l不需要进行+1,r 不需要进行-1。
- 最终我们需要的结果,就是l 或者 r, 也有可能找不到,也就是-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;移位的计算会比直接除法更快,所以通常用移位。
时间复杂度——O(logn)
空间复杂度——O(1)
1.严格有序数组查找==target的数字,没有返回-1
// 找到等于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;
}
2.有序数组查找刚好>=target的数字,没有返回-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;
}
3.有序数组查找刚好<=target的数字,没有返回-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;
}
// 找到第一个大于等于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;
}



