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

posted @ 2025-04-12 21:11  虾11  阅读(15)  评论(0)    收藏  举报