二分法
个人觉得二分法学习分两个阶段,第一个阶段是处理各种基本的二分场景,就是在数组中根据下标来搜索各种想要的数;第二阶段就是不再基于数组构建二分模型,而是各种搜索,我觉得很多题的难度不亚于动态规划。第二阶段只能靠多练习吧。
模板
二分基本型
二分的本质是,根据某一个判断(条件),在一个排序数组中检索某一个数,基本型的意思就是,这个判断有三种结果:大于、小于、等于,我们只需要返回使等于成立的情况。并且只需要和当前数进行比较,不需要和左右比较。
public int find(int[] arr, target){
//一些空值、基本情况的判断
checksomething();
int left = 0;
int right = arr.length - 1;
//保证区间中最少只能有一个数
while(left <= right){
int mid = left + (mid - left)/2;
//产生一个三个结果的比较
int res = check(arr[mid], target);
if(res == 0) return mid;
else if(res < 0) left = mid + 1;
else right = mid - 1;
}
return -1;
}
例题:就是在排序数组中找个数字
左区间的最大值
在某个条件下,数组划分为左右两个区间,求左区间的边界
public int find(int[] arr, target){
//一些空值、基本情况的判断
checksomething();
int left = 0;
int right = arr.length - 1;
int res=0;
//保证区间中最少只能有一个数
while(left <= right){
int mid = left + (mid - left)/2;
//判断当前值是否处于左区间中
boolean res = check(arr[mid], target);
if(res) {
left = mid + 1;
res = mid;
}else {
right = mid - 1;
}
}
return res;
}
例题:x的平方根
本题需要寻找x平方根的整数位,其实就是求:平方小于x的整数中,最大的那个数,也就是左区间最大值的问题。
右区间的最小值
这个情况上述情况可以等价互换
public int find(int[] arr, target){
//一些空值、基本情况的判断
checksomething();
int left = 0;
int right = arr.length - 1;
int res=0;
//保证区间中要有两个值
while(left < right){
int mid = left + (mid - left)/2;
//判断当前值是否处于左区间中
boolean res = check(arr[mid], target);
if(res) {
//①此时的区间大小限制是left < right,可能left = mid+1以后可能导致left=right,并且left还是处于左区间中就跳出了循环
left = mid + 1;
}else {
right = mid;
}
}
if(!check(arr[left],target)) return left;
else return -1;
}
例题:第一个错误版本
一个排序数组,左边都是正确的版本,右边都是错误的版本,寻找第一个错误版本,也就是右区间最小值问题