Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >算法:二分查找解题之核心思路(新颖)

算法:二分查找解题之核心思路(新颖)

原创
作者头像
CodeGoat24
修改于 2022-02-14 02:11:04
修改于 2022-02-14 02:11:04
60201
代码可运行
举报
运行总次数:1
代码可运行

二分查找的概述:

二分查找,也叫折半查找,一个比较简单的算法,能在有序数组中,以O(logn)的时间复杂度,快速找出符合要求的答案。在n非常庞大的情况下,相比于遍历数组,二分查找的效率是非常高的。 虽然二分查找的思路理解起来非常简单,但是真正到了做题的时候,如果不能彻底参透该算法,做到具体问题具体分析,可能就会漏洞百出了。正如网上资料所说:

“二分查找很好写,却很难写对,据统计只有10%的程序员可以写出没有bug的的二分查找代码。出错原因主要集中在判定条件和边界值的选择上,很容易就会导致越界或者死循环的情况。”

今天,我就来分享一下我做二分查找的核心思路和心得体会。


核心思路:

如果仅仅只是口头阐述,而不结合具体例子,想必大家是很难理解的,这里我找出了几个二分查找题型的不同种边界情况。带大家分析一下对应的做题思路。

常见的二分查找题解模样(伪代码)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
  int l = 0; //l <= 答案范围的最小值
  int r = n; //r >= 答案范围的最大值
  while(l < r){ //while循环条件 l < r 是可以做出任何题目的,所以不用做什么改变
    long long mid = (l + r) >> 1;  //mid有时应为 (l + r + 1) >> 1, 受下面l和r的取值影响
    if(a[mid] < target){ //这里的边界条件要根据具体题目而变, 且会影响下面l和r的取值
      l = mid + 1; //应结合具体请情况
    }else{
      r = mid; //应结合具体情况
    }
  }
  return l; //while循环条件为 l < r时,最终答案永远为l

上面只是列出了二分查找题解的基本架构, 并不是针对哪道题的模板

浏览我的注释,大家会发现,不同的二分查找题型,只是while循环里面的那块在微调,while循环外面的代码几乎一致

下面我来简单分析几种题型,希望大家能理解我的核心思路,做到一通百通.

注意: 我对二分查找题型分类的情况可能会和其他大佬不同,我是按照中值mid的取值对二分查找题型进行分类的,

因为mid取值只有两种情况: mid = (l + r) >> 1 或 mid = (l + r + 1) >> 1

若按照不同题目情境下, 不同的边界判断条件来讲解,小白会容易混乱。

而其实,在一个题目情境下,边界条件可以为nums[mid] < target,也可以为nums[mid] <= target等等,只是不同的边界条件,l和r的取值会不同而已。

所以根据边界条件来分情况会比较繁杂混乱,但按照mid的取值来分情况,那么只有两种情况。

1、中值 mid = (l + r + 1) >> 1的情况

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Solution {
public:
    int search(vector<int>& nums, int target) {
        int l = 0;
        int r = nums.size() - 1;
        //答案在数组元素下标为[l,r]的区间内
        while(l < r){
            long long mid = (l + r + 1) >> 1; //因为l=mid,所以在折半取值时,mid应优先取ceil((l+r)/2),避免死循环
            if(nums[mid] <= target){
                l = mid; //nums[mid]可能为答案
            }else{
                r = mid - 1;//nums[mid]肯定不是答案了,就将该mid踢出答案所在的[l,r]区间内
            }
        }
        if(nums[l] == target) return l;
        return -1;
    }
};

1、这题target可能不存在, 数组在l和r之间的所有元素都可能为答案.

2、判断时,当元素 <= target时,可能为答案,若元素 >target, 那么一定不可能是答案.
  因此,当nums[mid] <= target 时, mid指向的值可能为答案,因此l=mid, 若l=mid+1,则该元素就不在答案可能在的[l,r]区间了
  else 当nums[mid] > target 时, mid指向的值肯定不可能是答案,所有r = mid - 1,将该元素踢出[l,r]区间

3、分析到这里,l和r的分条件取值已经写好了, 只有mid的表达式还没确定.
  为什么是(l + r + 1) >> 1, 而不是(l + r) >> 1?

  根据上面l和r的取值可以判断.
  当l+1=r的情况下, 
  l所指的元素可能为答案,所以l在判断后会一直=mid,
  若mid = (l + r) >> 1, 那么mid会一直=l
  那么就陷入死循环了
  而mid = (l + r + 1) >> 1, 那么mid计算后就会等于r,此时就能正常得出答案.

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/binary-search

2、中值 mid = (l + r) >> 1的情况

给你一个排序后的字符列表 letters ,列表中只包含小写英文字母。另给出一个目标字母 target,请你寻找在这一有序列表里比目标字母大的最小字母。

在比较时,字母是依序循环出现的。举个例子:

如果目标字母 target = 'z' 并且字符列表为 letters = ['a', 'b'],则答案返回 'a'

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class Solution {
public:
    char nextGreatestLetter(vector<char>& letters, char target) {
        int n = letters.size();
        int l = 0;
        int r = n;
        //答案在数组元素下标为[l,r]的区间内
        while(l < r){
            long long mid = (l + r) >> 1;
            if(letters[mid] <= target){ //答案必须>target, 若letters[mid]<=target,则一定不可能是答案了
                l = mid + 1; //letters[mid]肯定不可能是答案了,就将该mid踢出答案所在的[l,r]区间内
            }else{
                r = mid; //letters[mid]可能为答案
            }
        }
        return letters[l % n];
    }
};

1、这题,当元素 > target时, 可能为答案,  若元素 <= target, 那么一定不可能是答案
2、当letters[mid] <= target 时, mid指向的值肯定不可能是答案,所以l = mid + 1,将该元素踢出[l,r]区间
  else 当letters[mid] > target 时, mid指向的值可能为答案,因此r=mid, 若r=mid-1,则该元素就不在答案可能在的[l,r]区间了

3、分析到这里,l和r的分条件取值已经写好了, 只有mid的表达式还没确定.
  为什么是(l + r) >> 1, 而不是(l + r + 1) >> 1?
  根据上面l和r的取值可以判断.
  当l+1=r的情况下, 
  r所指的元素可能为答案,所以r在判断后会一直=mid,
  若mid = (l + r + 1) >> 1, 那么mid会一直=r
  那么就陷入死循环了
  而mid = (l + r) >> 1, 那么mid计算后就会等于l,此时就能正常得出答案.

来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/find-smallest-letter-greater-than-target


总结:

认真理解后,是不是觉得按照mid取值对二分查找进行分类,相比于按照边界条件来分类会清晰许多呢?其实在做题时,

while(l < r){}以外的所有代码都是类似的, 根据题目情况稍微变一下就好了,如 l 和 r 的初始值为多少.

在写while循环里面的代码时, 完全可以先让mid = (l + r) >> 1, 然后往下写,当你选取了边界条件后, 并根据边界条件写出了 l 和 r 的取值等式后, 再分析特殊情况, 当l + 1 =r 时, 按照你写的l 和 r的取值等式, 是否会造成死循环, 如果会, 再将mid改为(l + r + 1) >> 1即可.

而 对于 l 的取值 l = mid+1 还是 l = mid, 对于 r 的取值 r = mid - 1还是 r = mid,都要根据你选取的边界条件来判断,不同边界条件,l和r的取值不同,但是思路都是一样的,若mid指向的元素可能为答案时,就不能将mid踢出答案所在的[l,r]区间,具体结合我上面的两个例子。

完结撒花~新人出道不易,希望大家可以喜欢+收藏哦!

如果上述分享有不妥之处,欢迎大家在评论区斧正

之后我还会陆续更新算法心得前后端技术的文章,欢迎大家关注支持~

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
基础算法---二分查找
二分查找的必要条件并不是单调,而是当我给定一个边界条件,然后左边满足这个边界条件,右边不满足这个边界条件,然后可以查找这个临界点,这就是二分查找
用户11305458
2024/10/09
1200
基础算法---二分查找
【优先算法】专题——二分查找算法
二分查找的特点就是细节最多,最容易写出现死循环的算法,但是理解之后还是非常简单的。
用户11375356
2024/12/28
2340
【优先算法】专题——二分查找算法
深究二分查找算法:从普通到进阶
欢迎来到我的编程之路新系列——算法学习仓。在这里,我们将一起拆解那些历经时间考验、无处不在、威力巨大的核心算法。
再睡一下就好
2025/06/11
1690
深究二分查找算法:从普通到进阶
二分查找经典题目
只有left > right时才能跳出循环,因为每次分割出来的区间的数是未知的,当left == right的时候仍然要检查
用户11039529
2024/09/24
1760
二分查找学习笔记
二分查找也称折半查找,它是一种效率较高的查找方法。二分查找,思路很简单,细节是魔鬼。
EmoryHuang
2022/10/28
2700
二分查找学习笔记
深度解析算法之二分查找(2)
题目链接 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
Undoom
2025/04/20
1770
深度解析算法之二分查找(2)
二分查找的细节总结
最近把leetcode上关于二分查找的简单题都刷差不多了,leetcode给我的技能树上点了二分查找
overme
2022/01/15
8190
二分查找的细节总结
LeetCode-二分查找
二分查找也称为折半查找,每次都能将查找区间减半,这种折半特性的算法时间复杂度为 O(logN)。
LittlePanger
2020/04/14
6380
算法细节系列(4):二分查找总结
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014688145/article/details/69094665
用户1147447
2019/05/26
9170
聊一聊二分查找法
还记得我们刚入行,接触算法的时候,一般都会从冒泡排序、二分查找开始入手算法,那小伙伴们会不会觉得这个算法太容易了,没有必要用一篇文章来讲解呢。
HUC思梦
2020/09/17
5690
聊一聊二分查找法
初识算法 · 二分查找(2)
本文的目标和之前的算法文章不太一样,像最开始的双指针算法,到滑动窗口算法,都是从题目中解析该算法原理,但是通过第一次的二分查找原理的算法,显然从题目中学习该算法的效果并不是很好,所以在本文中,博主将着重介绍二分查找的原理,对于最简单的朴素二分模板,我们肯定是不用介绍的,因为太简单了,更多信息,我们直接通过题目引出。
_lazy
2024/10/18
990
初识算法 · 二分查找(2)
我爱学算法之—— 二分查找(上)
现在我们来通过了解二分查找的算法题,来深入探究二分查找,以及什么时候能够使用二分查找。
星辰与你
2025/04/27
1330
我爱学算法之—— 二分查找(上)
算法细节系列(5):二分查找应用
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u014688145/article/details/69388673
用户1147447
2019/05/26
3820
一网打尽!二分查找解题模版与题型全面解析
二分查找算是最为基本的一个算法,也比较容易掌握。但是有些时候,我们可能因为一些细节的点没有考虑全而程序出错。
五分钟学算法
2019/08/16
9500
一网打尽!二分查找解题模版与题型全面解析
【刷题】 二分查找入门
总有一天,你会站在最亮的地方,活成自己曾经渴望的模样—— 苑子文 & 苑子豪《我们都一样 年轻又彷徨》
叫我龙翔
2024/04/02
1550
【刷题】 二分查找入门
【优选算法篇】寻找隐藏的宝藏:用二分查找打开算法世界的大门(上篇)
二分查找(Binary Search)是一种经典的算法,广泛应用于计算机科学中,尤其在处理有序数据时。其重要性体现在以下几个方面:
熬夜学编程的小王
2024/12/24
2330
【优选算法篇】寻找隐藏的宝藏:用二分查找打开算法世界的大门(上篇)
二分查找总结
二分查找是在每次匹配后,将查找的空间一分为二的算法,二分查找应该是有序的数组进行查找.
Tim在路上
2020/08/04
5120
19道leetcode二分查找算法
对于二分题,其实就是设定一个中间值 mid, 然后通过这个值进行一个判断 check(mid), 通过这个函数的返回值,判断将不可能的一半剪切掉;
hellocoder2028
2022/12/13
3320
二分查找算法详解
有一天阿东到图书馆借了 N 本书,出图书馆的时候,警报响了,于是保安把阿东拦下,要检查一下哪本书没有登记出借。阿东正准备把每一本书在报警器下过一下,以找出引发警报的书,但是保安露出不屑的眼神:你连二分查找都不会吗?于是保安把书分成两堆,让第一堆过一下报警器,报警器响;于是再把这堆书分成两堆…… 最终,检测了 log2N 次之后,保安成功的找到了那本引起警报的书,露出了得意和嘲讽的笑容。于是阿东背着剩下的书走了。
五分钟学算法
2019/06/18
1.1K0
二分查找算法详解
二分查找的通用模板
二分查找适用于对于有序数组的精确查找,例如从一个有序数组中找到指定元素的索引,可将时间复杂度从普通枚举的 O(n) 降至 O(log n) ,前提是数组必须是有序的,否则是没有办法使用二分查找的。二分查找的思想虽然简单,不过在实现过程中会有很多细节问题需要注意,例如判断循环是用left < right还是用left <= right,right是取最右的元素还是取数组的边界。本文想通过七个例题,约定一种规则或是模板,从此让写二分查找不再出现模棱两可的局面。
兜兜转转
2023/03/08
9920
相关推荐
基础算法---二分查找
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验