首页 > 编程语言 >二分查找算法

二分查找算法

时间:2024-03-26 14:33:06浏览次数:18  
标签:二分 arr target int 索引 算法 查找

二分查找算法思想

1、数组要求是有序的

2、定义左右边界索引l、r,中间索引m=(l+r)/2

3、判断arr[m]与待查找值target的大小,不断减少右边界索引r或者增加左边界索引l

 

基础版二分查找

(1)如果target<arr[m],则证明待查找值在中间索引左侧,减少右索引r=m-1,继续下一轮查找

(2)如果如果target>arr[m],则证明待查找值在中间索引右侧,增加左索引l=m+1,继续下一轮查找

(3)如果如果target=arr[m],则证明找到待查找值,返回对应索引

(4)循环结束了l>r还没找到,即没有待查找值,返回-1

 

基础版代码:

public static int binarySearch(int [] arr,int target){
    int l = 0, r=arr.length-1;
    while (l<=r){
        int m = (l+r)>>>1;
        if(target<arr[m]){
            r=m-1;
        }else if(arr[m]<target){
            l=m+1;
        }else {
            return m;
        }

    }
    return -1;

}

 基础版二分查找算法性能分析:

1、最好情况:O(1),第一次循环的值就是待查找值

2、最坏情况:O(log(n))

 

平衡版二分查找

在上述基础版二分查找算法中,如果待查找元素在最左侧L次循环的位置,则需要执行L次,即每次只需要执行if(target<arr[m])分支,而待查找元素在最右侧L次的位置时候,则需要执行2L次,即每次既需要执行if(target<arr[m])分支,又需要执行if(arr[m]<target)。元素在左侧和右侧的执行效率不一样,在左侧时查找速率更快,在右侧时查找速率要慢点,平衡版二分查找可以让左侧右侧的效率都保持一样,下面给出左右查找效率一样平衡版二分查找的实现思路:

1、左闭右开的区间,左边界索引l可能是查找目标,而右边界索引r不可能是查找目标

2、不在循环内找出,等循环只剩下l时,退出循环,在循环外比较arr[l]与target

public static int binarySearch2(int [] arr,int target){
    int l = 0, r=arr.length;
    while (1 <r-l ){
        int m = (l+r)>>>1;
        if(target<arr[m]){
            r=m;
        }else {
            l=m;
        }

    }
    if(arr[l]==target){
        return l;
    }else {
        return -1;
    }
}

 平衡版二分查找中,无论待查找元素在最左侧L次还是在最右侧L次的位置,都是只需要执行if(target<arr[m])分支,执行次数都是L次,时间复杂度最好最坏情况都是O(log(n)),没有最好情况O(1),因为最好最坏情况都是执行完循环在循环外边判断是否找到值,可以认为是不快不慢算法,待查找元素在靠左侧还是在靠右侧查找效率一样,而上面的基础版二分查找待查找元素在靠左侧的查找效率要高一些

 

最左、右侧匹配的二分查找(LeftRightMost)

场景提出:上述的二分查找算法中,返回的元素不一定就是最左匹配的元素,下面给出最左侧匹配算法的思路:

1、定义一个候选者变量

2、如果找到待查找元素,则将m赋值到候选者,记录候选者位置

3、继续缩小查找范围,重复更新候选者位置

 

最左侧匹配的二分查找(LeftMost)

public static int binarySearchLeftMost(int [] arr,int target){
    int l = 0, r=arr.length-1;
    int candidate=-1;
    while (l<=r){
        int m = (l+r)>>>1;
        if(target<arr[m]){
            r=m-1;
        }else if(arr[m]<target){
            l=m+1;
        }else {
            //找到元素了,不直接返回m,而是记录候选者位置,继续缩小查找范围
           candidate = m;
           r = m-1;
        }

    }
    return candidate;
}

 

最左侧匹配的二分查找(LeftMost)-返回特定值

在上述算法,没有找到目标值时,返回的-1实际没什么意义,我们有时候希望在没找到元素时,可以返回≥target的最左侧索引

public static int binarySearchLeftMost2(int [] arr,int target){
    int l = 0, r=arr.length-1;
    while (l<=r){
        int m = (l+r)>>>1;
        if(target<=arr[m]){
            //无论target是否找到还是没找到,都继续缩小范围
            r=m-1;
        } else {
            l=m+1;
        }
    }
    //返回的l是≥target的最左侧索引
    return l;
}

 如测试用例1:

System.out.println(binarySearchLeftMost2(new int[]{1,2,5,5,5,8,8,8,10,22},7));

该结果会返回5,就是返回比待查找值'7'大的最左侧的那个值'8'的索引位置

测试用例2:

System.out.println(binarySearchLeftMost2(new int[]{1,2,5,5,5,8,8,8,10,22},5));

返回的是2,即找到待查找值'5'最左侧的的索引位置

最右侧匹配的二分查找(RightMost)

public static int binarySearchRightMost(int [] arr,int target){
    int l = 0, r=arr.length-1;
    int candidate=-1;
    while (l<=r){
        int m = (l+r)>>>1;
        if(target<arr[m]){
            r=m-1;
        }else if(arr[m]<target){
            l=m+1;
        }else {
            //找到元素了,不直接返回m,而是记录候选者位置,继续缩小查找范围
            candidate = m;
            l = m+1;
        }

    }
    return candidate;
}

 

最右侧匹配的二分查找(RightMost)-返回特定位置

public static int binarySearchRightMost2(int [] arr,int target){
    int l = 0, r=arr.length-1;
    while (l<=r){
        int m = (l+r)>>>1;
        if(target<arr[m]){
            r=m-1;
        }else {
            //无论target是否找到还是没找到,都继续缩小范围
            l=m+1;
        }

    }
    //返回的l-1是≤target的最右侧索引
    return l-1;
}

 如测试用例1:

System.out.println(binarySearchRightMost2(new int[]{1,2,5,5,5,8,10,22},7));

该结果返回的是:4,返回的是比待查找值'7'小的最靠右的那个元素'5'的索引位置

测试用例2:

System.out.println(binarySearchRightMost2(new int[]{1,2,5,5,5,8,8,8,10,22},8));

 该结果返回的是:7,即找到待查找值'8'最右侧的的索引位置

 

 

最左、右侧匹配查找的应用

名词解析:前任:<targert的最靠右侧元素(rightMost),后任:>target的最靠左侧元素(leftMost),最近邻居:前任后任看哪个位置举例target更近(target-rightMost索引的值与leftMost索引的值-target作比较取更小的)

 

力扣704题:

 

 

力扣35题:使用leftMost

 

 

标签:二分,arr,target,int,索引,算法,查找
From: https://www.cnblogs.com/lrc123/p/18093400

相关文章

  • 【算法】【树】二叉搜索树中第K小的元素
    1 题目给定一个二叉搜索树的根节点 root ,和一个整数 k ,请你设计一个算法查找其中第 k 个最小元素(从1开始计数)。示例1:输入:root=[3,1,4,null,2],k=1输出:1示例2:输入:root=[5,3,6,2,4,null,null,1],k=3输出:3提示:树中的节点数为 n 。1<=k<=......
  • 【智能算法】野马优化算法(WHO)原理及实现
    目录1.背景2.算法原理2.1算法思想2.2算法过程3.结果展示4.参考文献1.背景2021年,Naruei等人受到野马自然社会行为启发,提出了野马优化算法(Wildhorseoptimization,WHO)。2.算法原理2.1算法思想WHO来源于野马的社会生活行为,主要包括小马驹的放牧行为、马的交配行......
  • 【智能算法】乌鸦搜索算法(CSA)原理及实现
    目录1.背景2.算法原理2.1算法思想2.2算法过程3.结果展示4.参考文献1.背景2016年,Askarzadeh等人受到乌鸦觅食自然行为启发,提出了乌鸦搜索算法(CrowSearchAlgorithm,CSA)。2.算法原理2.1算法思想CSA模拟了乌鸦进行觅食和藏匿食物的两种行为,CSA具有控制参数较少......
  • 【智能算法】秃鹰搜索算法(BES)原理及实现
    目录1.背景2.算法原理2.1算法思想2.2算法过程3.结果展示4.参考文献1.背景2020年,Alsattar等人受到秃鹰猎食自然行为启发,提出了秃鹰搜索算法(BaldEagleSearch,BES)。2.算法原理2.1算法思想BES主要分为三个阶段选择搜索空间、搜索空间猎物和俯冲捕获猎物。2.2......
  • 使用Go语言开发一个短链接服务:四、生成code算法
    章节 使用Go语言开发一个短链接服务:一、基本原理 使用Go语言开发一个短链接服务:二、架构设计 使用Go语言开发一个短链接服务:三、项目目录结构设计 使用Go语言开发一个短链接服务:四、生成code算法 使用Go语言开发一个短链接服务:五、添加和获取短链接 使用Go语言开......
  • C++11标准模板(STL) 算法(std::reverse)
    定义于头文件<algorithm>算法库提供大量用途的函数(例如查找、排序、计数、操作),它们在元素范围上操作。注意范围定义为 [first,last) ,其中 last 指代要查询或修改的最后元素的后一个元素。逆转范围中的元素顺序std::reverse1)反转[first,last)范围中的元素顺序表......
  • 【不确定性】【关键场景辨别算法】基于关键场景辨别算法的两阶段鲁棒微网优化调度(Matl
     ......
  • [算法]分割等和子集算法 & bitset容器应用
    LeetCode416.分割等和子集1题目描述给你一个只包含正整数的非空数组nums。请你判断是否可以将这个数组分割成两个子集,使得两个子集的元素和相等。1.1输入测试示例1:输入:nums=[1,5,11,5]输出:true解释:数组可以分割成[1,5,5]和[11]。示例2:输入:nums=[1,2,3,5]......
  • Manacher 算法
    开个坑,后续补解析classSolution{public:intcountSubstrings(strings){intn=s.size();stringt="$#";for(constchar&c:s){t+=c;t+='#';}n=t.size();......
  • 嵌入式算法开发系列之pid算法
    文章目录概要一、PID算法原理二、PID算法模型三、PID算法实现方法四、PID算法C语言实现示例五、PID算法在嵌入式系统中的应用小结概要PID(Proportional-Integral-Derivative)控制算法是一种常用的闭环控制算法,广泛应用于嵌入式系统中的控制器设计。今天张工将深入探讨......