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

二分查找算法

题目要求:

给定目标值指定数组, 数组为升序数组 ,在数组中查找到目标值 ,如果成功返回下标,失败则返回-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;

    }
}

总结:

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

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

相关推荐
Keven_112 小时前
算法札记:SPFA判负环算法的证明
算法
什巳2 小时前
JAVA练习278- 和为 K 的子数组
java·学习·算法·leetcode
Jerry2 小时前
LeetCode 347. 前 K 个高频元素
算法
Young Doro3 小时前
SAC 算法
线性代数·算法·机器学习
罗超驿3 小时前
2.算法效率的核心密码:时间复杂度和空间复杂度详解
java·数据结构·算法
:-)3 小时前
算法-堆排序
数据结构·算法·排序算法
星马梦缘4 小时前
算法设计 期末复习笔记
算法·动态规划·二分图·最小生成树·线性规划·最大流