二分查找-java

二分查找

基础版

arr是待查找升序数组,target是待查找元素

基础版的left和right两个所指向的元素都是待查找值

public static int binarySearchBasic(int[] arr, int target) {
    int left = 0, right = arr.length - 1; //设置指针和初始值
    while (left <= right) { //left 到 right 中间有东西
        int middle = (left + right) / 2;
        if (target < arr[middle]) { //目标在左边
            right = middle - 1;
        } else if (arr[middle] < target) { //目标在右边
            left = middle + 1;
        } else {   //找到了
            return middle;
        }
    }
    return -1;  //没找到
}

两个改进点:

  • int middle = (left + right) / 2;
    //改进后,使用无符号右移运算符
    int middle = (left + right) >>> 1;
    
    • 如果数组数据过大,(left + right) / 2的计算结果可能就超过int的表示范围,会由正变负
    • (left + right) >>> 1,不会出现这种问题
  • 返回值为-1,没有什么特殊意义。可以根据返回值算出插入点

    • 参考jdk的Arrays工具类
    • 返回值改为"-(left + 1)"。left可以表示插入点,这里为了避免索引0位置产生歧义,返回加一之后的相反数
    • 插入点计算方法是:“Math.abs(返回值+1)”

改动版

left指向的还是待查找值

right只是作为边界,不指向待查找值

public static int binarySearchAlternative(int[] arr, int target) {
    int left = 0, right = arr.length; //第一处
    while(left < right){	//第二处
        int middle = (left + right) >>> 1;
        if(target < arr[middle]){
            right = middle; //第三处
        }else if(arr[middle] < target){
            left = middle + 1;
        }else{
            return middle;
        }
    }
    return -(left + 1);	//如果没有该值,返回该值插入点加一的相反数
}

平衡版

基础版和改动版对于while循环中选择语句的执行次数不平衡。

​ 具体含义是,如果查找的数是不存在的,且当该值小于数组最小值和大于数组最大值的时候执行的比较次数是不一样的

public static int binarySearchBalance(int[] arr, int target) {
    int left = 0, right = arr.length;
    while (1 < right - left) {   //范围内待查找的元素个数 > 1 时
        int middle = (left + right) >>> 1;
        if (target < arr[middle]) { //目标在左边
            right = middle;
        } else { //目标在middle 或者 右边
            left = middle;
        }
    }
    return (target == arr[left]) ? left : -1;
}

二分查找高级用法

LeftMost

01

查找升序数组,某个重复元素最左边的位置的索引。不存在返回-1

public static int binarySearchLeftmost1(int[] arr, int target) {
    int left = 0, right = arr.length - 1;
    int candidate = -1;
    while(left <= right){
        int middle = (left + right) >>> 1;
        if(target < arr[middle]){
            right = middle - 1;
        }else if(arr[middle] < target){
            left = middle + 1;
        }else{
            //更改候选位置
            candidate = middle;
            right = middle - 1;
        }
    }
    return candidate;
}

02

查找升序数组,如果目标值存在目标值索引位置,如果目标值重复存在,返回最左边的索引

​ 如果目标值不存在,返回大于目标值最左边的索引位置

即,返回大于等于目标值的最左边位置的索引

public static int binarySearchLeftmost2(int[] arr, int target) {
    int left = 0, right = arr.length - 1;
    while(left <= right){
        int middle = (left + right) >>> 1;
        if(target <= arr[middle]){
            right = middle - 1;
        }else if(arr[middle] < target){
            left = middle + 1;
        }
    }
    return left;
}

RightMost

01

查找升序数组,某个重复元素最右边的位置的索引。不存在返回-1

public static int binarySearchRightmost1(int[] arr, int target) {
    int left = 0, right = arr.length - 1;
    int candidate = -1;
    while(left <= right){
        int middle = (left + right) >>> 1;
        if(target < arr[middle]){
            right = middle - 1;
        }else if(arr[middle] < target){
            left = middle + 1;
        }else{
            //更改候选位置
            candidate = middle;
           	left = midddle + 1;
        }
    }
    return candidate;
}

02

查找升序数组,如果目标值存在目标值索引位置,如果目标值重复存在,返回最右边的索引

​ 如果目标值不存在,返回小于目标值最右边的索引位置

即,返回小于等于目标值的最右边位置的索引

public static int binarySearchRightmost2(int[] arr, int target) {
    int left = 0, right = arr.length - 1;
    while (left <= right) {
        int middle = (left + right) >>> 1;
        if (target < arr[middle]) {
            right = middle - 1;
        } else {
            left = middle + 1;
        }
    }
    return left - 1;
}

LeftMost和RightMost的方式二的高级用法

几个名词

image-20221125174155058

范围查询

基础版leftmost和基础版rightmost应用

  • 查询 x < 4 x \lt 4 x<4 0.. l e f t m o s t ( 4 ) − 1 0 .. leftmost(4) - 1 0..leftmost(4)1
  • 查询 x ≤ 4 x \leq 4 x4 0.. r i g h t m o s t ( 4 ) 0 .. rightmost(4) 0..rightmost(4)
  • 查询 4 < x 4 \lt x 4<x,$rightmost(4) + 1 … \infty $
  • 查询 4 ≤ x 4 \leq x 4x l e f t m o s t ( 4 ) . . ∞ leftmost(4) .. \infty leftmost(4)..∞
  • 查询 4 ≤ x ≤ 7 4 \leq x \leq 7 4x7 l e f t m o s t ( 4 ) . . r i g h t m o s t ( 7 ) leftmost(4) .. rightmost(7) leftmost(4)..rightmost(7)
  • 查询 4 < x < 7 4 \lt x \lt 7 4<x<7 r i g h t m o s t ( 4 ) + 1.. l e f t m o s t ( 7 ) − 1 rightmost(4)+1 .. leftmost(7)-1 rightmost(4)+1..leftmost(7)1

求排名 l e f t m o s t ( t a r g e t ) + 1 leftmost(target) + 1 leftmost(target)+1

索引从0开始, 排名是从1开始的

  • t a r g e t target target 可以不存在,如: l e f t m o s t ( 5 ) + 1 = 6 leftmost(5)+1 = 6 leftmost(5)+1=6
  • t a r g e t target target 也可以存在,如: l e f t m o s t ( 4 ) + 1 = 3 leftmost(4)+1 = 3 leftmost(4)+1=3

求前任(predecessor) l e f t m o s t ( t a r g e t ) − 1 leftmost(target) - 1 leftmost(target)1

前任的索引

  • l e f t m o s t ( 3 ) − 1 = 1 leftmost(3) - 1 = 1 leftmost(3)1=1,前任 a 1 = 2 a_1 = 2 a1=2
  • l e f t m o s t ( 4 ) − 1 = 1 leftmost(4) - 1 = 1 leftmost(4)1=1,前任 a 1 = 2 a_1 = 2 a1=2

求后任(successor) r i g h t m o s t ( t a r g e t ) + 1 rightmost(target)+1 rightmost(target)+1

后任的索引

  • r i g h t m o s t ( 5 ) + 1 = 5 rightmost(5) + 1 = 5 rightmost(5)+1=5,后任 a 5 = 7 a_5 = 7 a5=7
  • r i g h t m o s t ( 4 ) + 1 = 5 rightmost(4) + 1 = 5 rightmost(4)+1=5,后任 a 5 = 7 a_5 = 7 a5=7

求最近邻居

  • 前任和后任距离更近者
  • 20
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值