【LeetCode笔记】二分查找专项


二分查找 = 折半查找

时间复杂度O(logN)

最标准的查找

  1. 初始化 左边界

    int len = arr.length - 1;
    int l = 0; int r = len-1;
    
  2. while循环判断条件

    这个是 左闭右闭区间 (我常用的)

     while (left <= right) 
    

    还有 左闭右开 (不常用)下面说

  3. 获取 区间的中间坐标 mid

    int mid = l + (r - l)/2;
    // 为什么不能写 (l+r)/2?
    // 因为 
    int l = Integer.MAX_VALUE-1;
    int r = Integer.MAX_VALUE-1;
    // 那这个时候 l+r会出现溢出
    
  4. 左右边界的确定

    if(nums[mid] == target){
        return mid;
    }else if(nums[mid] < target){
        l = mid+1;
    }else(target < nums[mid]){
        r = mid-1;
    }
    

二分查找的两大基本原则

由👆可见,

  1. 二分查找每次都要 缩减搜索区域,左右边界的缩小
  2. 缩减方式要合理,不能将潜在答案缩减出去

当已知存在target时,我们可以直接通过 大小判断 和 左右边界 = mid±1获得,因为这种判断 和缩减方式 都是没有问题的,但是若出现 变体 的话,则需要 适当更改缩减方式

变形一:(已知存在目标值)最左边的目标值

// 查找第一个值等于给定值的元素
private int firstEquals(int[] arr, int target) {
    int l = 0, r = arr.length - 1;
    while (l < r) {
        int mid = l + ((r - l) >> 1);
        if (arr[mid] < target) l = mid + 1;
        else r = mid; // 收缩右边界不影响 first equals
    }
    if (arr[l] == target && (l == 0 || arr[l - 1] < target)) return l;
    return -1;
}

变形二:(已知存在目标值)最右边的目标值

// 查找最后一个值等于给定值的元素
private int lastEquals(int[] arr, int target) {
    int l = 0, r = arr.length - 1;
    while (l < r) {
        int mid = l + ((r - l + 1) >> 1);
        if (arr[mid] > target) r = mid - 1;
        else l = mid; // 收缩左边界不影响 last equals
    }
    if (arr[l] == target && (l == arr.length - 1 || arr[l + 1] > target)) return l;
    return -1;
}

变形四:大于目标值的第一个数

744. 寻找比目标字母大的最小字母 - 力扣(LeetCode) (leetcode-cn.com)

public char nextGreatestLetter(char[] letters, char target) {
    int l = 0;
    int r = letters.length-1;
    if(letters[r]<=target){
        return letters[l];
    }
    while(l<r){
        int mid = l + (r-l)/2;
        if(letters[mid]<=target){
            l = mid+1;
        }else{
            r = mid;
        }
    }
    return letters[l];
}

变形五:大于等于目标值的第一个数

👇:若存在目标值 则返回 最左边的目标值 即 第一个目标值

若不存在目标值 则返回 大于目标值的第一个数下标

若整个数组都小于目标值 则返回 nums.length

35. 搜索插入位置 - 力扣(LeetCode) (leetcode-cn.com)

// 查找第一个大于等于给定值的元素
public int searchInsert(int[] nums, int target) {
    int l =0;
    int r = nums.length;
    while(l<r){
        int mid = l+(r-l)/2;
        if(nums[mid]>=target){
            r = mid;
        }else{
            l = mid+1;
        }
    }
    return l;
}

变形七:小于目标值的最后一个数

剑指 Offer 53 - I. 在排序数组中查找数字 I - 力扣(LeetCode) (leetcode-cn.com)

需要注意!需要注意!需要注意!需要注意! 👇

因为初始值l=0,若整个nums ≥ target,那么 最后的 l还是0 l=0 不会变。

if(l==0) 需要判断一下 nums[l]target的大小关系

private int find (int[] nums,int target) {
    // 小于目标值的最后一个数
    int l =0;
    int r =nums.length-1;
    while(l<r){
        int mid = l+(r-l+1)/2;
        if(nums[mid]>=target){
            //当中间值 ≥ 目标值 因为我们不需要目标值 所以要缩减 即r = mid -1;
            r = mid-1;
        }else{
            l = mid;
        }
    }
    return l;// 若整个 nums ≥ target 那么l=0;
}

变形三:小于等于目标值的最后一个数

情况一: 存在目标值 会输出 最后一个目标值

**情况二:**不存在目标值 会输出 小于目标值的最后一个数

需要注意!需要注意!需要注意!需要注意! 👇

// 查找最后一个小于等于给定值的元素
private int lastLessOrEquals(int[] nums, int target) {
    int l = 0;
    int r = nums.length - 1;
    while (l < r) {
        int mid = l + (r - l + 1)/2;
        if (nums[mid] > target){//我要查找 小于等于target的元素 那么 大于target的需要全部删除
            r = mid - 1;
        } 
        else l = mid; //nums[mid] <= target 
    }
    // 注意 l 可能不变 需要最后做个对比 
    if (arr[l] <= target && (l == arr.length - 1 || arr[l + 1] > target)) return l; // <=
    return -1;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值