4.12学习(二分查找)
点击查看代码
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] nums = new int[n];
for(int i = 0; i < n; i++) {
nums[i] = sc.nextInt();
}
int target = sc.nextInt();
// 1 2 3 4 5 6
int res1 = search(nums, target);//找到第一个大于等于target的数 >=target
int res2 = search(nums,target+1);//找到第一个大于target的数 >target 等价于>=target+1
int res3 = search(nums,target)-1;//找到最后一个小于target的数 <target 等价于(>=target)-1
int res4 = search(nums,target+1)-1;//找到最后一个小于等于target的数 <=target等价于(>target)-1
System.out.println(res1);
}
//找到第一个大于等于target的数
public static int search(int[] nums, int target) {//lower_bound
int l=-1, r=nums.length;//(l,r)
while(l+1<r){
int mid = l+(r-l)/2;
if(nums[mid]>=target){
r=mid;
}else{
l=mid;
}
}
return r;
}
}
二分中while循环的条件:记住循环条件一定是区间不为空
这里的区间是什么?可以理解为还没有与target做比较的数。
根据定义的l,r决定,上面代码中我定义l=-1,r=nums.length,也就是(l,r)两边都是开的。
我们的区间为(l,r),所以要想让该区间不为空,就要满足l+1<r
怎么写nums[mid]与target比较完大小后l和r的移动?
nums[mid]和target比较过了,所以区间中不用包括mid,l和r是区间的左右端点但是取不到(我们的区间是两边开的),直接让l和r赋值为mid。
如果是[l,r]这样定义的区间,则l应该为多少,r应该为多少?
如果是[l,r)这样定义的区间,则l应该为多少,r应该为多少?
l=mid+1,r=mid-1
l=mid+1,r=mid
这2种写法要去考虑+1,-1,不如开区间的写法,直接全部赋为mid
int res1 = search(nums, target);//找到第一个大于等于target的数 >=target
int res2 = search(nums,target+1);//找到第一个大于target的数 >target 等价于>=target+1
int res3 = search(nums,target)-1;//找到最后一个小于target的数 <target 等价于(>=target)-1 (>=target 的前一个位置)
int res4 = search(nums,target+1)-1;//找到最后一个小于等于target的数 <=target等价于(>target)-1 (>target 的前一个位置) 然后可以用第二个不等式转换一下,结果为(>=target+1)-1

求<3的最后一个数,相当于求<=2的最后一个数,又等价于求>=3的第一个数位置-1
求<=3的最后一个数,相当于求>=4的第一个数位置-1

浙公网安备 33010602011771号