leetcode算法总结 —— 二分查找


下面我总结一个二分查找通用模版,为二分查找神器,使用该模版解决力扣上的二分查找几乎所有的问题。

二分算法执行条件

  1. 给定的有序数组 ,我们要遍历每个数。
  2. 判断遍历的每个数是否符合给定的条件。(比如判断遍历的每个数是否等于target)

这时我们就要使用二分算法。他的时间复杂度是O(logN) 要优于O(n)因为O(logN)效率几乎和O(1)相等。具体可以看我的置顶博客,时间复杂度比较图

这是引出二分的原理模版,通过该模版我们可以清楚了解二分是如何执行的。

判定第一个不符合条件的

比如给定数组{1,1,1,1,1,0,0,0,0,0} 快速找到第一个0 我们考虑使用二分
left也就是查找不符合条件的第一个值

    //left 和 right 是我们取到到第一个值和最后一个值,左右都是闭的都可以取到的有效值
    int left = 1;
    int right = n; 
    while (left <= right) {
    
    
        int mid = left + ((right - left) >> 1);
        //重点:主要是这里进行判断条件的思考
        if(当前如果等于1符合条件)) {
    
    //是正确的,则我们向右找。
            left = mid + 1;
        } else {
    
     //否则向左找
            right = mid - 1;
        }
    }
    //重点:mid是符合if条件的最后一个数,left = mid+1,循环完之后返回的是left为 不符合if条件 的第一个index,从这里就衍生出下面的模板了
    return left;

典型例题

    1. 第一个错误的版本
    1. 寻找峰值(同278,注意判断条件)
    1. 爱吃香蕉的珂可(同278)
    1. 猜数字大小
    1. x 的平方根

查找目标值及边界

//该模板适用于二分查找:在递增排序的数组中查找目标值target
//1.如果目标值不存在,则返回的left是target应该在的位置
//2.如果目标值存在且有重复if (nums[mid] < target),则返回target第一个位置(左边界)即不符合if条件的第一个值,也就是target = nums[mid]的第一个值
//3.如果目标值存在且有重复if (nums[mid] <= target),则返回大于target第一个位置(右边界)即不符合if条件的第一个值,也就是target > nums[mid]的第一个值
    int left = 0;
    int right = nums.size() - 1; //left 和 right 是我们取到到第一个值和最后一个值,左右都是闭的都可以取到的有效值
    while (left <= right)
    {
    
    
        int mid = left + ((right - left) >> 1); //防止越界,并且比除2提升速度
        if (nums[mid] < target) {
    
      //找左边界,则返回target第一个位置(左边界)
        // (nums[mid] <= target)  //找右边界,求的是大于target的第一个数下标
            left = mid + 1;        //因为mid的数不是解,所以取mid+1
        } else {
    
    //right左移
            right = mid - 1;
        }
    }
    //mid是符合if条7件的最后一个数,left = mid+1,
    //则left返回的是不符合条件的第一个位置
    return left;

典型例题

    1. 搜索插入位置 (模板(nums[mid] < target),元素可重复)
    1. 二分查找 (模板查找固定值,35稍微改动)
    1. 寻找比目标字母大的最小字母(模板(nums[mid] <= target),35稍改)
    1. 在排序数组中查找元素的第一个和最后一个位置 (完美模板训练)
    1. 供暖器
    1. 搜索二维矩阵(两次二分)

旋转数组

根据左右区间递增判断

典型例题

        int left = 0;
        int right = nums.size()-1;
        while(left <= right) {
    
    
            int mid = left + ((right - left) >> 1);
            if(nums[right] < nums[mid]) {
    
    //这时说明目标值在右侧,我们需要右移
                left = mid + 1;//右移下标
            } else if(nums[right] > nums[mid]) {
    
    
                right = mid;
            } else {
    
     //相等,则说明有重复元素,去重
                right--;
            }
        }
    1. 搜索旋转排序数组
    1. 寻找旋转排序数组中的最小值
    1. 寻找旋转排序数组中的最小值-ii

参考资料:https://leetcode-cn.com/problems/search-insert-position/solution/te-bie-hao-yong-de-er-fen-cha-fa-fa-mo-ban-python-/

猜你喜欢

转载自blog.csdn.net/chongbin007/article/details/111794602