二分法
在网上搜,能看见比较详细的二分法的介绍,但是笔者还是想去梳理一下,因为想要真正理解二分法的代码和二分法的原理是不一样的。首先,看一个比较常用的二分法算法。
public int binarySearch(int nums[],int target){
Arrays.sort(nums);
int left=0,right=nums.length-1;
while(left<=right){
int mid=(left+right)/2;
if(nums[mid]==target){
return mid;
}
else if(nums[mid]>target){
right=mid-1;
}
else {
left=mid+1;
}
}
return left;
}
我们主要从两个边界问题来考虑这个函数会怎么样:
-
如果nums的取值范围在[a,b],并且target值属于[a,b],但是target不等于nums中的任意元素。对于这种情况下,我们能够得到binarySearch返回一个index值,但是nums[index]并不对于target。
如nums=[0,1,2,3,4,5,6,7,8] target=2.5
最终输出的值为3,因为找不到target。轮次 left right mid 1 8 4 2 3 1 3 2 3 2 4 3 3 3 5 3 2 2 -
如果nums的取值范围在[a,b],并且target值不属于[a,b],则会出现超过数组的index
如nums=[0,1,2,3,4,5,6,7,8] target=9
轮次 left right mid 1 8 4 2 5 8 6 3 7 8 7 4 8 8 8 5 9 8 8 最终输出的值是9,找不到index。
这个方法我们再找最终输出的index是否满足要求,需要判断index是否在nums数组范围的同时判断nums[index]是否对于target,这样子就比较麻烦,所以需要改进一下算法
public int binarySearch(int nums[],int target){
Arrays.sort(nums);
int left=0,right=nums.length-1;
while(left<right){
int mid=(left+right)/2;
if(nums[mid]==target){
return mid;
}
else if(nums[mid]>target){
right=mid;
}
else {
left=mid+1;
}
}
return left;
}
该方法就不会越界,但是还是需要判断nums[index]是否等于target。
- 那么对于nums=[0,1,2,3,4,4,4,5,6,7],target=4,并且我想得到最左边的4的下标,我们怎么改进算法呢?
public int binarySearch(int nums[],int target){ Arrays.sort(nums); int left=0,right=nums.length-1; while(left<right){ int mid=(left+right)/2; if(nums[mid]>=target){ right=mid; } else { left=mid+1; } } return left; }
-
同理,我们想找到最右边的4的下表,我们应该怎么改进呢?
可以思考一下,然后见下面的答案:
注意这个mid是如何取值的,本质上也是相对于去最左边值的对偶关系public int binarySearch(int nums[],int target){ Arrays.sort(nums); int left=0,right=nums.length-1; while(left<right){ int mid=(left+right)/2+(left+right)%2; if(nums[mid]<=target){ left=mid; } else { right=mid-1; } } return right; }
-
那么介绍完了二分法了之后,可以尝试做一下leetcode题目
https://leetcode-cn.com/problems/minimum-time-to-complete-trips/