我在使用二分法时经常遇到一些问题,比如 while的终止条件是left < right
呢还是left <= right
或者是其中类似right = mid
或right = mid -1
,总是很迷糊应该怎样写,这次我决定好好的将这个问题解决。
1. 题目
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。
class Solution {
public int searchInsert(int[] nums, int target) {
if(nums[0] > target){
return 0;
}
if(nums[nums.length-1] < target){
return nums.length;
}
int left = 0,right = nums.length;
int mid = 0;
while(left < right){
mid = (left + right)/2;
if(nums[mid] > target){
right = mid;
}else if(nums[mid] < target){
left = mid +1;
}else{
return mid;
}
}
return left;
}
}
2. 确定区间
一个名为nums
数组的长度为n
,那它最大的索引下标为n-1
我们一般使用下面两种方法表示:
1.左闭右开的方法 [0,n)
left = 0, right = n
2. 左闭右闭的方法 [0,n-1]
left = 0, right = n-1
对于区间的不同定义是影响下面我们边界条件处理的
3. 左闭右开的写法
3.1 while中止条件
我们使用 [0,n)
这种情况下left是不可能取得right的值,如一个只有一个值的数组[2]
,区间是[0,1)
left 不可能取值1,假如left能够取值为1,这是区间变为[1,1)
肯定是错误的。while的终止条件如下:
while(left < right)
3.2 中点获取
mid = left + (right - left)/2
3.3 区间收缩情况
3.3.1 nums[mid] > target
当中点的值nums[mid]大于target时,target落在中点的左侧,这时我们应该将right向左移动,情况如下:
- right = mid
- right = mid - 1
我们应该使用哪一个呢,注意此时我们是左闭右开的区间,右边界值是不能取到的。
用方式一,是可行的
方式二,mid-1
位置上的值我们就不可能取到了,那mid-1
位置上是不是target
我们也无法知道,不可行。
3.3.2 nums[mid] < target
当中点的值nums[mid]小于target时,target落在中点的右侧,这时我们应该将left向右移动,情况如下:
- left = mid
- left = mid +1
我们是左闭右开的区间
方式一:如果mid
本来就等于left
,那么区间没有收缩。所以跳出区间, 必须要mid+1
。实例如下:
[1,3,5,7,9] target = 6;
left = 0 right = 5 mid = 2 5 < 6
left = 2 right = 5 mid = 3 7 > 6
left = 2 right = 3 mid = 2 5 < 6
死循环了
方式二:此时我们已经确定中点位置的值小于target,所以直接使用left = mid +1
4. 左闭右闭的写法
4.1 while中止条件
我们使用 [0,n-1]
这种情况下left能够取得right的值,如一个只有一个值的数组[2]
,区间是[0,0]
是合法的。此时while的终止条件如下:
while(left <= right)
4.2 中点获取
mid = left + (right - left)/2
4.3 区间收缩情况
4.3.1 nums[mid] > target
当中点的值nums[mid]大于target时,target落在中点的左侧,这时我们应该将right向左移动,情况如下:
- right = mid
- right = mid - 1
我们应该使用哪一个呢,注意此时我们是左闭右闭的区间,右边界值是能够取到的。
此时我们已经确定mid
位置的值一定不是target
所以使用right = mid -1
4.3.2 nums[mid] < target
当中点的值nums[mid]小于target时,target落在中点的右侧,这时我们应该将left向右移动,情况如下:
- left = mid
- left = mid +1
我们是左闭右闭的区间
此时我们已经确定mid
位置的值一定不是target
所以使用left = mid +1
5. 最后
这就是我的这边文章了,欢迎留言,让我们共同进步吧。