☰
LeetCode刷题总结:二分查找模板与热门题复刷策略
2026/10/5 8:13:08 网站建设 项目流程

做LeetCode刷题的人很多,但真正把题目转化成自己能力的人并不多。我见过太多人刷了三百题,遇到新题还是没思路,也见过一些人只刷了一百来题,却能应付大部分面试算法环节。差别不在数量,在于有没有形成自己的知识总结体系。这篇是我这个系列的第24篇,照例不写流水账,只聊那些真正值得反复消化的知识点和题目背后的套路。

1. 为什么"总结"比"刷题"更决定上限

1.1 刷题数量不等于掌握程度

先说一个我观察了很久的现象。很多人刷题的方式是:打开题解,看明白思路,自己敲一遍,通过,下一题。这种流程走完五十题之后会有一个明显的错觉——"这些题我都见过"。但真到面试或周赛时,换个壳就认不出来了。

我自己的体会是:一道题做三遍并总结规律,比做三道不同的题收获更大。第一遍是认识解法,第二遍是脱离题解独立完成,第三遍是隔一两周后回来复现,并且顺手把这个题归入自己的知识框架。这个"归入框架"的动作,才是总结的核心。

这里分享一个很实用的指标:如果一道题你做完之后,能在三天后不看任何资料,用五分钟之内讲清楚这道题的思路、时间复杂度和关键边界条件,那这道题才算真正消化了。讲不清楚的,基本都是当时"背"下来的,而不是"理解"的。

1.2 知识点的归类方式决定检索效率

很多人觉得总结就是抄一遍题解或者记个博客,其实不然。有效的总结方式应该像整理书架一样,按主题放书,而不是按时间顺序堆书。

我习惯把LeetCode知识点分成这么几个大方向:

  • 数据结构类:数组、链表、栈、队列、哈希表、堆、树、图
  • 算法思想类:二分、双指针、滑动窗口、回溯、动态规划、贪心、分治
  • 技巧类:位运算、前缀和、差分、单调栈、并查集、拓扑排序

每做完一道题,我先问自己一个问题:这道题如果让我给一个初学者讲思路,我会先讲数据结构还是先讲算法思想?答案一般就是这道题的主标签。然后再往上挂一到两个副标签,比如"哈希表 + 滑动窗口"、"二分 + 贪心判断"。

这样做的价值在于:当你遇到新题时,大脑检索的路径是"这题像是哪一类",而不是"我之前做过哪道有点像的题"。前者是结构化记忆,后者是零散记忆。面试时你就能感受到这个差异有多关键。

2. 二分查找:从"爱吃香蕉的狒狒"看到通用的三种考法

2.1 一道经典题的完整拆解

热点里提到了"073爱吃香蕉的狒狒",这是LeetCode 875题,可以说是二分查找应用题的经典代表,很多公司面试都喜欢拿它当热身题目。题目本身很简单,一堆香蕉,每一堆数量不同,狒狒一小时吃一堆,但可以选择吃多少根。给定总时间H,求最小的每小时吃香蕉速度K。

这道题暴露了两个典型的二分误区。第一个误区是有人一上来就想对数组本身做二分——实际上这里二分的对象是"吃的速度"这个值域,跟香蕉数组本身无关。第二个误区是搞不清楚左边界和右边界怎么收敛,容易在边界条件上死循环。

我当时做这道题时,第一反应也是直接模拟,从速度1开始往上试,计算每个速度是否能在H小时内吃完。这样做当然能出结果,但K最大可以到十的九次方级别,逐个试效率太低,根本过不了。

正确做法是对K做二分。K的最小值是1,最大值可以设置为香蕉堆中最大的那一堆数量(因为速度超过最大值没有意义,一小时只能吃一堆)。每次取中间值,写一个判断函数,模拟狒狒以这个速度吃完所有香蕉需要多少小时。判断函数的核心很直接:每一堆需要的时间是(pile + K - 1) / K,向上取整。如果总时间小于等于H,说明这个速度可行,但可以试试更小的速度,所以收缩右边界;否则收缩左边界。

这个"能行就试试更小"的二分思路,很多人写着写着就绕晕了。我自己的记忆口诀很简单:判断函数返回 true 时,说明当前值满足条件,但不一定是最优解,所以往更优的方向继续找。在这种"找最小可行值"的题目里,更优的方向就是左半边。

2.2 二分查找的三种考法对应关系

这题做完之后,我回头整理了一下LeetCode里关于二分的考法,发现可以归成三类:

考法一是经典二分搜索,直接在一个有序数组中找目标值,这是最基础的题型。比如在排序数组中查找元素的第一个和最后一个位置,本质上就是写两个二分,一个找左边界,一个找右边界,看似基础,写起来却很容易出错。

考法二是答案值域二分。就是上面的狒狒题这类,题目不给一个明确的"数组"让你搜索,而是给一个问题,让你在可能的答案范围里找一个边界值。之前很流行的"分割数组的最大值"也是这类题,我做的过程中最大的感受是:这类题的核心难点不在二分逻辑本身,而在于判断函数的设计。判断函数写不好,二分框架再熟练也没用。

考法三是在隐含单调性上二分。这种情况最隐蔽,题目里没有明说有序,但仔细分析后能发现单调性。比如求一个数的平方根,看起来跟二分没关系,但数字范围本身天然有序。又比如一些"第K小元素"的问题,通过对值域二分,用计数器统计比当前值小的元素个数,再逐步逼近答案。

2.3 我沉淀下来的二分模板

因为这类题做多了,我整理了一个自己的二分模板,基本覆盖了80%以上的场景:

def binary_search(nums, target): left, right = 0, len(nums) - 1 while left <= right: mid = left + (right - left) // 2 if nums[mid] == target: return mid elif nums[mid] < target: left = mid + 1 else: right = mid - 1 return -1

这个模板最重要的是mid = left + (right - left) // 2这一步。我见过有人直接写(left + right) // 2,当数字很大时会溢出。虽然LeetCode的测试用例一般不会卡这个点,但养成好习惯总没坏处。

而对于"答案值域二分",我的模板是这样的:

def feasible(mid): # 根据题目设计判断逻辑,返回是否可行 pass left, right = min_val, max_val while left < right: mid = (left + right) // 2 if feasible(mid): right = mid else: left = mid + 1 return left

这个模板里while left < right和right = mid、left = mid + 1的搭配,是"找最小可行值"的标准写法。如果题目变成"找最大可行值",就把逻辑反过来,用left = mid和right = mid - 1。记住这两套写法后,绝大多数问题都能套进去。

注意:这类题真正烧脑的是 feasible 函数。做狒狒这题时,feasible 只需要模拟吃香蕉过程;但做"第K小"类题目时,feasible 可能就是一个双指针或者堆的应用。所以刷二分时,与其把时间花在背框架上,不如多练几道不同场景的 feasible 设计。

3. 热门100题里,最有复刷价值的是这几类

3.1 看似简单,却藏满细节的题

"LeetCode热门100题"是很多人的必刷清单。但我的经验是:热门题不等于简单的题,更不等于做完就能会的题。就拿"两数之和"来说,大部分人用暴力解过了就不再回头看了。但如果你换个角度思考——为什么可以用哈希表?核心原因是"查找一个与当前值互补的数"这个动作,哈希表可以做到O(1)的查找。把一个O(n平方)的问题降到O(n),这就是数据结构改变算法复杂度的最典型案例。

这类"藏满细节"的题,我特别推荐重点关注这样几道:

  • "两数之和":哈希表空间换时间的思想启蒙
  • "接雨水":双指针、单调栈、动态规划三种解法都能做,思路跨度极大
  • "LRU缓存机制":哈希表+双向链表的结构设计题,面试高频
  • "合并K个升序链表":优先队列的典型应用

每一道都值得反复刷三遍以上。就拿LRU来说,我在面试中见过不少候选人能说出"哈希表+双向链表"这个答案,但真到手写代码时,节点删除、头尾指针更新这些细节一写就乱。原因就是练得太少,只看懂了思路,没有形成肌肉记忆。

3.2 热门题里的思维升级路径

热门100题的价值,我认为不在于题目本身难度,而在于它们构建了一条思维升级的路径。比如你做完了"两数之和",再看"三数之和",会发现排序+双指针这个思路其实是对暴力解法的一种聪明剪枝;你做完"三数之和"再做"四数之和",又会发现完全可以将三数之和的解法封装起来,套一层循环而已。

这个"套壳升级"的规律,在动态规划里更典型。从"爬楼梯"到"打家劫舍",再到"最长递增子序列",本质上都是定义状态、找转移方程。真正理解了这种递进关系,刷题就会轻松很多。

所以我一直建议,刷热门100题时不要按题号顺序刷,按主题递进刷。先把哈希表相关的刷完,再刷双指针相关的,再刷动态规划的。这样你能感受到知识之间的关联,而不是孤立地记每一道题的答案。

3.3 我重刷热门题的节奏安排

关于重刷,我自己有一个很具体的节奏策略,分享出来供参考:

第一遍刷的时候,不追求独立写出代码,但要求理解解法并能口述思路。第二遍安排在两周之后,这一遍要求独立写出代码,不看题解。第三遍安排在面试前或周赛前,快速过一遍,每道题只给自己十分钟,能AC就过,不能AC就标记为薄弱题,然后专项重练。

这样做下来,热门100题里真正需要第三遍的人可能只有30道左右,这30道就是你的盲区所在。三轮下来,你对这些题的理解深度和背答案完全不是一个级别。

4. LeetCode周赛430:竞赛题暴露的常见知识盲区

4.1 周赛题型分布与备战策略

周赛430的题解是最近的热词,我也去打了这场。说实话,周赛和日常刷题最大的区别在于:日常刷题你有充足时间慢慢想,周赛却是在时间压力下逼你做出取舍。这个取舍能力,恰恰是面试中最实用的能力。

以我的经验来看,周赛的四道题通常是这样分布的:

  • Q1:签到题,往往是考基本功的,比如模拟、字符串处理,基本是5-10分钟内要搞定
  • Q2:稍微需要一点思考的题,可能是哈希表、贪心或者简单DP,15分钟左右要搞定
  • Q3:开始上难度,经常涉及数据结构或者更复杂的思维,可能需要二三十分钟
  • Q4:综合压轴题,经常是图论、高级数据结构或者复杂的动态规划,很多高手也可能卡住

备赛策略上,我的做法很固定:每周三开始看本周题目相关的知识点,提前预热;周赛当天提前静坐几分钟,让脑子进入状态;打比赛时先快速过一遍四道题,判断哪些是硬骨头,合理分配时间。

4.2 周赛430里让我印象深刻的卡点

周赛430这场,我复盘时发现自己卡在了一道中等难度的题目上,原因很典型:题目描述看起来像个模拟题,但实际上需要的是一个数据结构来优化时间复杂度。我一开始按模拟思路写,写了大几十行还各种边界出错,后来意识到应该用堆来维护一个有序结构,换了一个思路,代码量反而少了一半。

这个经历很有代表性。它反映了竞赛题的一个常见套路:题干里给的约束条件往往暗示了正确的解法方向。比如数据范围到达十的五次方,一般就不可能再用O(n平方)的暴力解法;如果涉及频繁取最大值或最小值,多半用堆;如果涉及区间和,考虑前缀和或树状数组;如果是处理括号匹配或嵌套结构,优先想栈。

我把这个"根据数据范围推断算法"的思路总结成了自己的选型表:

数据范围可接受的复杂度常用思路
n ≤ 20O(2ⁿ)状态压缩、回溯
n ≤ 1000O(n²)双重循环、动态规划
n ≤ 10⁵O(n log n)排序、二分、堆、树状数组
n ≤ 10⁶O(n)哈希表、双指针、滑动窗口

这张表虽然不绝对,但作为预判方向非常管用。周赛里时间就是金钱,如果一开始就选对了算法,就算实现过程中有些小问题,整体节奏也会从容很多。

4.3 从周赛中提取可复用经验的方法

打完周赛后最重要的一步是复盘。我的复盘不只是看一下题解,而是给自己三个问题的回答:

第一,这四道题里,哪一道是我原本可以做出来却没有做出来的?原因是什么?是思路没对上,还是实现细节出了问题?第二,哪一道是我花了太长时间?这部分时间能不能通过更好的选型省下来?第三,有没有哪道题用到了一种我此前没见过的技巧?如果有,把这道题归类并记录下来。

做完这三步,才算是把一场周赛消化透了。我见过一些人打完周赛只看排名,排名涨了就开心,排名掉就沮丧,却从不复盘。到头来打了几十场周赛,水平还是原地踏步,那就是最可惜的。

5. 我自己在刷题总结中踩过的坑和磨出来的方法

5.1 笔记记了等于没记的误区

我早期刷题时也写过很详细的笔记,每道题都抄一遍题解,配上思路解析,写完之后自我感觉特别好。但后来复习时发现,我抄的那些东西根本没有进入我的脑子,看到题还是想不起来思路。

后来我反思了一下,发现问题的本质在于笔记的方式太"抄写化"了,缺少了主动输出。抄写题解时大脑是被动接收的,而真正的理解需要主动重组信息,用自己的语言把解题逻辑讲一遍,甚至讲给一个虚拟的"初学者"听。

所以后来我改成了"题后三行"法。每道题做完,不抄题解,只用三行字总结这道题的最优解套路、关键边界条件和这道题和自己已有知识点的关联。这三行字是逼自己想出来的,不是抄来的。效果完全不一样。

5.2 用标签体系替代线性笔记

现在我的刷题记录是完全标签化的,每个标签代表一个知识切片,题目只是这个切片下的一个案例。比如"单调栈"这个标签下,我会挂上"柱状图中最大的矩形""每日温度""接雨水"等题;每道题挂上去时,我都会在题目旁标注"这道题的关键特征是找最近更大/更小值"。

这样一来,复习的时候就特别高效。想看单调栈,点进去一次能复习七八道题;看的时候还能对比它们之间的异同,加深理解。相比那种"第1天到第300天每天记一道题"的日志式笔记,这种按知识点组织的结构不知道好用多少倍。

还有一点值得提的是:隔一段时间,要把笔记里相似的知识点做合并整理。比如"滑动窗口"和"双指针"看似是两种思路,其实很多题既可以用双指针也可以用滑动窗口,多做几道你就会发现它们之间的关联边界,这时候合并成一个大标签,反而思路更清晰。

5.3 时间分配上的一个具体建议

最后聊一下刷题的时间分配,这也是我踩坑踩出来的经验。大部分人刷题是"有时间就狂刷几小时,没时间就一周不碰",这样的节奏效果最差。因为算法的思维模式是需要持续保持的,间断太久再回来会非常生涩。

我更建议的模式是每天固定四十分钟到一小时,雷打不动。前十五分钟复习昨天的错题或写一道之前做过的题,中间三十分钟做一道新题,最后五分钟整理笔记和标签。这样一天一天积累下来,你实际投入的总时间可能不比那些周末猛刷的人少,但掌握程度会扎实很多。

6. 一套可以复制的刷题总结迭代流程

在写了二十多篇总结之后,我逐渐把整个流程固化下来了。这里分享给大家,你可以直接拿来用,也可以根据自己的习惯调整。

6.1 每周固定做一次"知识地图"刷新

每天做的都是零散的题目,每周就应该做一次汇总。我一般会在周末花一小时,打开这一周做过的所有题目,按知识点重新过一次,看这一周在哪些方向有新增,哪些方向还薄弱。

这个动作有点像看地图更新。你每天刷题是在地图上画点,周末汇总就是把点连成线,看出这周的整体走向。如果没有这个步骤,你只知道"这周做了十五题",但不太清楚自己的知识结构在往哪个方向变化。

每次刷新时,我会问自己三个问题:这周新增了哪些知识点?有哪些题做错了但错因相同?下周的重点方向是什么?回答完这三个问题,下一周的刷题计划自然就出来了。

6.2 建立"错题必做三遍"机制

错题是刷题中最宝贵的资产,因为它是最精准地标记你思维盲区的地方。我的机制是:第一次做错,隔三天重做;再错,隔两周再重做;还错,那就说明这个知识点不只是"不会"的问题,而是理解深度不够,需要专门去补这个知识点的基础,而不是反复做同一道题。

这个机制帮我省了很多无谓的重复。很多人在错题上反复打转,同一个错误犯十次,就是因为缺少"升级"机制——错了就再做,做对了当时觉得会了,过两周又忘了。而我的三遍机制每次重做之间都隔了足够长的时间,能真正检验长期记忆效果。

6.3 从"会做题"到"会讲题"

最近一年我开始尝试一个更高阶的训练:把自己做过的经典题目写成讲稿,用最通俗的方式讲给别人听。这个过程远比想象中有效——你自认为懂的东西,一旦试图讲清楚,会发现很多地方经不起推敲。

比如有一次我以为自己完全理解了"最长公共子序列"的动态规划解法,但当我想解释清楚"为什么dp[i][j]的定义能保证状态转移的正确性"时,发现自己其实卡了很久。这个卡住的地方,正是我的理解盲区。讲完之后,这道题才算真正内化了。

所以我特别建议大家,找一两个同样在刷题的朋友,互相讲题。不用讲太复杂的题,中等难度的题就够了。能把一道中等题讲得对方点头,说明你理解得够深;讲不明白的地方,就是你该回去补课的地方。


一路刷到第24篇总结,最大的感受是:LeetCode的意义从来不是"刷过多少题",而是你通过这些题,构建了多强的算法思维。我做这套总结笔记,本质上是想给自己留下一个"可检索的大脑外挂"。如果你也在刷题,不妨试试这个思路——从今天开始,不急着做新题,先花一点时间把最近做过的题按知识点归归类,也许收获比你预期的大得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询