【二分查找算法以及变种Leftmost、Rightmost查找及其应用】

学习目标:

掌握二分查找算法以及变种Leftmost、Rightmost查找,刷Leetcode相关练习题。

  • 掌握基本二分查找算法
  • 掌握Leftmost、Rightmost查找算法
  • 练习Leetcode相关练习题

基本二分查找算法:

前提:有序数组
算法思想:每次比较数组中间位置元素与待查target元素,若中间位置元素与target相等,则返回索引表示找到,当中间位置元素值大于target,表示待查元素在target左面,此时查找target左边数组,当中间位置元素小于target,表示待查元素在target右边,此时查找target右边元素。

public static int binarySearchBasic(int[] a, int target) {
        int i = 0, j = a.length - 1;    // 设置指针和初值  
        while (i <= j) {                // 表示target与ij范围内包含ij比较
            int m = (i + j) >>> 1;
            if (target < a[m]) {         // 目标在左边
                j = m - 1;
            } else if (a[m] < target) { // 目标在右边
                i = m + 1;
            } else {                    // 找到了
                return m;
            }
        }
        return -1;
    }

Leftmost二分查找算法:

前提:有序数组
算法思想:在二分查找算法思想上考虑了重复元素的影响,返回的是最左侧的重复元素。

public static int binarySearchLeftmost(int[] a, int target) {
    int i = 0, j = a.length - 1;
    int candidate = -1;
    while (i <= j) {
        int m = (i + j) >>> 1;
        if (target < a[m]) {
            j = m - 1;
        } else if (a[m] < target) {
            i = m + 1;
        } else {//此时表示查找到了但考虑重复元素影响
            candidate = m; // 记录候选位置
            j = m - 1;     // 继续向左
        }
    }
    return candidate;
}

改进:当查找到时返回最左侧索引,当查找不到时放回待插入位置索引

public static int binarySearchLeftmost2(int[] a, int target) {
        int i = 0, j = a.length - 1;
        while (i <= j) {
            int m = (i + j) >>> 1;
            if (target <= a[m]) {
                j = m - 1;
            } else {
                i = m + 1;
            }
        }
        return i;
    }

Rightmost二分查找算法:

前提:有序数组
算法思想:较Leftmost返回重复元素的最右边元素

public static int binarySearchRightmost(int[] a, int target) {
    int i = 0, j = a.length - 1;
    int candidate = -1;
    while (i <= j) {
        int m = (i + j) >>> 1;
        if (target < a[m]) {
            j = m - 1;
        } else if (a[m] < target) {
            i = m + 1;
        } else {
            candidate = m; // 记录候选位置
            i = m + 1;	   // 继续向右
        }
    }
    return candidate;
}

改进:当查找到时返回最右侧索引,当查找不到时放回待插入位置索引

public static int binarySearchRightmost2(int[] a, int target) {
        int i = 0, j = a.length - 1;
        while (i <= j) {
            int m = (i + j) >>> 1;
            if (target < a[m]) {
                j = m - 1;
            } else {
                i = m + 1;
            }
        }
        return i - 1;
    }

Leetcode相关练习题

在这里插入图片描述
解题思路:Leftmost改进版,找到时返回重复元素最左侧索引,找不到时放回待插入位置

class Solution {
    public int searchInsert(int[] a, int target) {
        int i = 0, j = a.length - 1;
        while (i <= j) {
            int m = (i + j) >>> 1;
            if (target <= a[m]) {
                j = m - 1;
            } else {
                i = m + 1;
            }
        }
        return i;
    }
    
}

在这里插入图片描述
思路:一次leftmost找左位置,一次rightmost找右位置,这里不需要插入,只需要找到,所以在leftmost中要有candidate记录当前找到的中间位置

class Solution {
    public int[] searchRange(int[] nums, int target) {
        int x = left(nums, target);
        if(x == -1){
            return new int[]{-1,-1};
        }else{
            return new int[]{x, right(nums, target)};
        }

    }
    public int left(int[] a, int target){
        int i = 0, j = a.length-1;
        int candidate = -1;
        while(i <= j){
            int m = (i + j) >>> 1;
            if(target < a[m]){
                j = m-1;
            }else if(target > a[m]){
                i = m +1;
            }else{
                candidate  = m;
                j = m-1;
            }

        }
        return candidate;

    }

     public int right(int[] a, int target){
        int i = 0, j = a.length-1;
        int candidate = -1;
        while(i <= j){
            int m = (i + j) >>> 1;
            if(target < a[m]){
                j = m-1;
            }else if(target > a[m]){
                i = m +1;
            }else{
                candidate  = m;
                i = m+1;
            }

        }
        return candidate;

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值