二分查找算法概述&通用模板

二分查找算法

题目要求:

给定目标值指定数组, 数组为升序数组 ,在数组中查找到目标值 ,如果成功返回下标,失败则返回-1。(时间复杂度尽可能短)

题目解析以及核心思路:

题目解析:

在数组中寻找目标值,只需要遍历数组一次即可, 此时的时间复杂度为O(N)。


在这里我们介绍一种快捷的查找算法--二分算法。

这种查找算法时间复杂度可以缩减到O(logN)。

算法思想: 对于某一组数组,根据题目要求的特殊规律选取某点, 把数组分成两部分, 并且根据题目的特殊规律舍去一组,在另一组中继续重复进行操作,直到查找到点为止。
核心思路:

特殊规律:升序数组(从中选取一个点与目标值比较:

目标值大于这个点,则一定大于左侧所有点,下一次选取点在右侧(往大的点去取)

目标值小于这个点,则一定小于右侧所有点,下一次选取点在左侧(往小的点去取))

若遇到等于情况:直接返回该点即可(就是要找的目标值)

若无法找到目标点:返回-1


细节:

  • 此处求mid使用的计算方式是"防止数据溢出",直接(left+right)/2相加很可能造成数据溢出出现数组越界的问题

代码实现:

java 复制代码
public int search(int[] nums, int target) {
        int left=0;
        int right=nums.length-1;
        while(left<=right){
            int mid=left+(right-left)/2;//防止溢出
            if(nums[mid]>target){
                right=mid-1;
            }
            if(nums[mid]<target){
                left=mid+1;
            }
            if(nums[mid]==target){
                return mid;
            }
        }
        //只要能找到一定会在上面完成返回,运行到这,已经是找不到的情况
        return -1;
    }

总结:

根据特殊规律来制定选取点与目标值的判断条件即可。

本题的二分性:升序数组->元素数值大小递增,由此来分成一个大值部分,一个小值部分

模板代码:

java 复制代码
while(left<=right){
if(//视特殊规律而定){
left=mid+1;
  }
else if(//视特殊规律而定){
right=mid-1;
  }
else{
return mid;
  }
}

查找左,右端点的二分查找算法

题目要求:

题目要求在一个给定不递减数组 中,寻找目标值的第一个出现的下标,最后一个出现的下标。

可以归结为:"寻找由指定值组成的区间的左端点和右端点"。

题目解析以及核心思路:

题目解析:

相当于寻找左,右端点。 因此我们使用两次二分查找算法,来寻找左右端点


解题准备:

  • 二段性:若对于查找左端点,二段性为"小于t或者大于等于t";若对于查找右端点,二段性为"大于t或者小于等于t"
    核心思路:

1.查找左端点:

根据二段性:

  • 当numsmid<目标t,向右区间(更大的数)去寻找

  • 当numsmid>=目标t,向左区间(更小或者相同的数)去寻找==>当前指向数,可能就是目标值t,但是不知道其位置(前?中?末?),因此right不能越过mid(找首下标)

  • 循环条件:left<right, 循环结果是left=right时,如果再继续循环会执行第二步骤,造成死循环

  • 求中点操作:left+(right-left)/2。 数组元素个数为偶数时,取靠左的为中点,若选择靠右的为中点,会执行第二步骤,死循环


    2.查找右端点: 根据二段性:

  • 当numsmid>目标t,向左区间(更小或者相同的数)去寻找

  • 当numsmid<=目标t,向右区间(更大或者相同的数)去寻找==>当前指向数,可能就是目标值t,但是不知道其位置(前?中?末?),因此left不能越过mid(找末尾下标)

  • 循环条件:left<right, 循环结果是left=right时,如果再继续循环会执行第一步骤,造成死循环

  • 求中点操作:left+(right-left+1)/2。 数组元素个数为偶数时,取靠右的为中点,若选择靠左的为中点,会执行第一步骤,死循环


补充: 循环结束,记得判断numsleft?=target,依此为返回数组赋值

代码实现:

java 复制代码
class Solution {
    public int[] searchRange(int[] nums, int target) {
        //返回数组
        int[] a={-1,-1};
        //为空时直接返回[-1,-1]
        if(nums==null||nums.length==0){
            return a;
        }
        int left=0;
        int right=nums.length-1;
        //查找区间左端点
        while(left<right){
            int mid=left+(right-left)/2;
            if(nums[mid]>=target){
                right=mid;
            }
            else{
                left=mid+1;
            }
        }
        //此时left==right就是结果,与目标值比较相同则返回下标
        if(nums[left]==target){
            a[0]=left;
        }
        //查找区间右端点
        left=0;
        right=nums.length-1;
        while(left<right){
            int mid=left+(right-left+1)/2;
            if(nums[mid]<=target){
                left=mid;
            }
            else{
                right=mid-1;
            }
        }
         //此时left==right就是结果,与目标值比较相同则返回下标
        if(nums[left]==target){
            a[1]=left;
        }
        return a;

    }
}

总结:

查找一个区间的左端点代码模板如左侧,查找一个区间的右端点代码模板如右侧

本人才疏学浅,若有错误还请诸位指正,希望本文能帮助到大家,后续还有关于二分查找应用的题目的博客文章,教大家如何使用模板,敬请期待。

相关推荐
月华路2 小时前
G1 GC 对数组与大对象(Humongous)的处理
java·jvm·算法
我想走路带风2 小时前
LRU和最长前缀和(计算机网络算法)
计算机网络·算法
M78佐菲2 小时前
Linux学习笔记:进程
linux·笔记·学习·算法
徐小夕4 小时前
表格、文档、甘特、大屏、表单一站打通:pxcharts超级表格4.0正式上线!
前端·算法·github
TechLee5 小时前
跨语言加解密总对不上?这个纯 Go 神库让 AES/RSA 与 PHP、Java 100% 互通
java·后端·算法
月华路6 小时前
G1 新生代对象晋升老年代:实现机制与 GC 日志
java·jvm·算法
万法若空7 小时前
排列组合恒等式
c++·算法
Nil2087 小时前
leetcode 105从前序和中序遍历序列构造二叉树
算法·leetcode·职场和发展
一直C7 小时前
【数据结构】哈希表+算法复杂度与经典排序查找(C语言)
java·linux·开发语言·数据结构·算法·ubuntu·散列表
淡海水7 小时前
04-02-哈希-Dictionary-TKey-TValue-上-核心数据结构
数据结构·算法·c#·哈希算法·编译·字典·dictionary