Hot 100打卡第10天:滑动窗口经典题与高效刷题避坑指南
hot100打卡走到第10天说实话这是历次刷题计划里我坚持得最久的一次。倒不是忽然变自律了而是每天雷打不动的流程已经固定下来打开Hot 100清单挑一道当天要做的题20分钟拆思路拆不出来就参考答案最后亲手写一遍、记进打卡表格。这套动作的累计效果比“今天我多刷了三题”这种成就感更踏实。Day10正是一个合适的节点把前几天的选题逻辑、做题方法和踩过的坑一起整理出来给正在刷题或者准备面试的朋友一个参考。如果你刚开始按Hot 100刷题后面的安排可以直接照抄如果你已经刷到中间阶段希望下面的内容能帮你少走几步弯路。1. 从第1天到第10天Hot 100打卡的节奏感1.1 为什么把Hot 100当成主线刷题最怕的不是题目难而是没有方向。今天翻一本算法书明天跟着某个教程走后天又回头刷旧题时间花了不少知识还是散的。Hot 100的价值在于它直接把高频的、有代表性的题摊开摆在你面前。这份清单覆盖了数组、链表、哈希表、字符串、树、图、动态规划、贪心、二分、滑动窗口等主流题型几乎每个常见算法模板都有一道或多道典型题目撑着。这意味着只要按清单往下刷你是在用有限的题量去覆盖一个相对完整的知识面而不是随机抓题。对准备面试的人来说Hot 100还有一个隐藏价值很多面试题的原始模型就藏在这些题里。实际面试中遇到的题目往往不会完全一样但会变体、会组合万变不离其宗。把Hot 100里的典型题吃透相当于手里握着一套基础模具面试官换包装你也能认出来。对刚入门的人来说这份清单也省去了“今天该刷什么”的决策成本每天只需要回答一个问题今天做哪一道这一个省力恰恰是能坚持到第10天的重要前提。1.2 前10天的目标不是数量是“触发感”很多人在头几天最容易犯的错就是追求数量。一天五道简单题觉得进度飞快一周后回头看发现只记得做过什么不记得怎么做更不知道每道题的解法能迁移到哪里。我在前10天给自己定的目标非常单一不追求刷完多少题而是训练一种看到题型就触发对应思路的直觉。举个例子看到“最长子串”“连续区间”这种词自然想滑动窗口看到“有序数组”“查找”自然想二分看到“两数之和”“去重”自然想哈希表。这种触发感才是刷题真正在积累的东西。为了量化这个目标我准备了一张简单的打卡表字段是日期、题目编号、题型分类、是否独立完成、卡住的位置、核心思路一句话。每天做完题顺手填上十分钟都用不了。别小看这个动作它把“我好像学了很多”这样的模糊感觉变成了可以回看的进度。到第10天我翻这张表时能一眼看出自己在哪类题上反复卡壳后面的练习方向也自然清楚了。记录本身不产生能力但记录会告诉你该往哪儿使力。1.3 前10天一定会经历的两个心态波动第一个波动来自横向比较。网上总有“一个月刷完Hot 100”的帖子看了难免焦虑。我的实际体验是别人刷得快不代表掌握得好一个人每天无脑抄答案刷五题和我每天认真吃透一题一周后的差距其实不明显。只要总题量和时间允许慢一点没有关系真正有关的是每一题有没有留下自己的结论。第二个波动是碰到难题后的自我否定。第10天前后难度已经从前几天的入门题过渡到中等题某道题看答案都看不太懂很正常。我的处理办法是先跳过把它标成“二刷重点”等后续同类题积累到两三道再回头统一解决。Hot 100不是按难度排序的清单偶尔遇到一座陡峰绕过去不代表放弃只是换个更适合自己的进攻路线。心态稳住了打卡才走得远。2. 第10天实战一道滑动窗口题串起的知识闭环2.1 这道题为什么值得拆第10天我挑了一道很经典、也很有代表性的字符串题给定一个字符串找出其中不含重复字符的最长子串长度。这道题在Hot 100里属于“钉子户”几乎所有按清单刷过的人都会遇到。它的覆盖面很广单看题干你很难第一时间判断该用哪一类算法需要先意识到这是滑动窗口问题然后用哈希表辅助更新窗口边界。一次练习串起了字符串、哈希表、双指针、滑动窗口四块内容。这类题更讨喜的地方是它有一条清晰从暴力到优化的演进路径。暴力解很简单但性能很差优化解很短但逻辑细节很吃理解。很多类似的题只是“会做”容易“做对”难这道题的边界条件恰好能把隐性错误全部钓出来。所以拿它作为Day10的拆解对象非常合适。2.2 从暴力解到最优解的完整思考路径暴力思路不难想到枚举所有子串的起点和终点对每个子串检查是否含重复字符记录不重复子串的最大长度。时间复杂度是O(n³)量级虽然通过哈希集合可以把查重优化一些但总体仍然过不了大数据尤其是题目输入长度一旦上万基本必超时。关键在于找到重复发生时的规律。假设当前窗口是[left, right]子串不含重复字符。下一步把right右移如果新字符和窗口内的某个字符重复了那么所有以这个新字符为右端点的合法子串其左端点必须越过这个重复字符上一次出现的位置。如果只靠这个信息已经可以写出一个循环不断把left右移直到窗口内没有重复字符right继续往右走全程不回退。这个思路就是滑动窗口窗口收缩的核心。再进一步为了不靠循环去数left要走多远可以用哈希表记录每个字符最近一次出现的下标。当发现新进来的字符已经出现过并且它上一次出现的位置仍在当前窗口内就把left一次性跳到那个位置加一。为什么加一因为上一个相同字符本身不能留在窗口里窗口从它的下一位开始时才不会包含重复字符。写成伪代码就是遍历每个right检查当前字符若有重复则更新left再更新哈希表下标最后用right-left1刷新答案。2.3 手写代码最容易翻车的三个点第一顺序不对。算窗口长度必须放在重复字符处理完之后。如果先把长度算出来窗口可能还是非法状态答案会偏大。这个错误在“字符串中有多处重复字符”的用例下特别隐蔽。第二left的更新忘了和旧left取最大值。哈希表里存的是字符上一次出现位置这个位置可能已经在窗口左边很远的地方了如果不和当前left比较直接用它加一就可能让left回退窗口里重新混入重复字符。我第一次写这题时只判断了字符是否在哈希表里没有判断位置是否在窗口内结果跑特定的用例时多算了一位排查了一会儿才意识到。第三边界条件。空字符串、单个字符、全部字符相同这三种情况最简单的测试一跑就露馅。养成写完代码立刻用最短用例过一遍的习惯比事后辛辛苦苦debug效率高得多。2.4 滑动窗口模板的识别与应用边界滑动窗口不是万能工具它有明显的适用条件问题对象必须是连续的子段并且区间扩张和收缩有明确的状态变化。在Hot 100里凡是题干中出现“最长子串”“最短子数组”“覆盖所有字符”“最多替换k次”这类关键词都值得优先往滑动窗口方向想。识别模板的能力恰恰来自前几天的“触发感”训练这题就是很典型的正反馈。但也要注意它的边界如果要求目标不是连续片段或者需要全局范围的最值滑动窗口就不一定适用。比如涉及“子序列”的问题通常走动态规划而不是滑窗。第10天做题时我在题目类型后补了一句“为什么能用滑窗”逼自己说清楚原因这个习惯在后续刷题里帮了大忙到了Day20以后识别速度明显提升。3. 代码落地两版本实现与语言选型3.1 存储频次收缩窗口 vs 存储下标直接跳实现方式一用哈希表存储字符出现次数。窗口每加入一个新字符就把对应次数加一一旦某个字符次数超过一就进入收缩阶段用while循环把left右移同时减少left位置字符的计数直到窗口重新合法。这种写法胜在逻辑直观适合刚接触滑动窗口时理解过程代价是代码稍长最坏情况下left可能连续移动多次但总的移动次数仍然是O(n)。实现方式二用哈希表存储每个字符最近出现的下标。遇到重复字符时直接用下标跳转更新left代码非常短。下面是我整理的两个版本def length_of_longest_substring(s: str) - int: char_count {} left 0 ans 0 for right, ch in enumerate(s): char_count[ch] char_count.get(ch, 0) 1 while char_count[ch] 1: char_count[s[left]] - 1 left 1 ans max(ans, right - left 1) return ans版本二def length_of_longest_substring(s: str) - int: pos {} left 0 ans 0 for right, ch in enumerate(s): if ch in pos: left max(left, pos[ch] 1) pos[ch] right ans max(ans, right - left 1) return ans两种写法的时间复杂度都是O(n)空间上都是O(字符集大小)。区别在于版本一更容易解释“窗口如何收缩”的逻辑版本二在面试白板上写起来更简洁。我的建议是新手阶段两个版本都写一遍体会它们的差别熟练掌握后优先使用版本二因为它把“窗口是否合法”的判断浓缩在一个if里不容易写乱。3.2 Python与Java的选择建议主语言选什么其实没有标准答案。我自己的习惯是主用Python因为写起来快、表达直观适合在解题阶段快速验证思路看题解时偶尔对照Java版本学习更多工程化的写法。如果你准备去参加以Java为主要语言的技术面试直接用Java刷题更贴近真实工作因为面试时你大概率也要现场写Java代码。两种语言我都写了下面对照Java版本的核心逻辑和Python完全一致public int lengthOfLongestSubstring(String s) { MapCharacter, Integer pos new HashMap(); int left 0; int ans 0; for (int right 0; right s.length(); right) { char ch s.charAt(right); if (pos.containsKey(ch)) { left Math.max(left, pos.get(ch) 1); } pos.put(ch, right); ans Math.max(ans, right - left 1); } return ans; }有一点很重要定好主语言之后不要频繁切换。刷题阶段积累的所有API、模板、写法都绑定在一种语言上频繁换语言会导致每次都要花时间回忆基本语法反而打断了算法思路的训练。Java选手要背熟HashMap的getOrDefault、containsKey、putPython选手要熟记dict的get方法、defaultdict、set的in判断。这些API不需要专门背写着写着就自然记住了。3.3 测试用例怎么设计才不心虚很多人刷题时只跑题面给的示例跑过就算通过了这是很危险的习惯。示例用例往往只覆盖正常路径不会刻意暴露错误的边界处理。我当时给自己列了一组必备用例每一道字符串题都会先跑一遍空字符串应该返回0单字符应该返回1所有字符全部相同比如“aaaa”正确答案是1重复字符出现在窗口内部的情况比如“abca”答案是3能检验left是否回退的用例比如“abba”正确答案是2如果left更新逻辑有问题很容易算成3还有题面示例之外的乱序重复“aab”答案是2。这一套跑完基本能覆盖多数隐藏问题。设计测试用例的核心思路是主动构造“最恶心”的输入。你不需要知道平台的隐藏用例是什么只需要站在实现者的对立面假设代码容易在哪里出错就编辑对应的用例去验证。尤其是滑动窗口这类边界清晰的题left的回退、新增字符的重复、窗口内已有元素的变化每个点都可以用一个用例试探。养成这个习惯后不只是这题整个Hot 100刷下来代码通过率会稳定很多。4. 打卡十天后沉淀下来的复盘方法论4.1 错题本的正确记法错题本不是抄题也不是抄答案。我前10天摸索出的记录格式是日期、题型、题干一句话复述、我的错误点、最优解的核心思路、时间复杂度、三天后是否还能独立写出。这个格式逼着我做两件事一是用最精炼的话概括题干训练抓题眼的能力二是精确描述错误点而不是笼统写“不会”。举个例子某道关于合并区间的题我第一次没做出来记录时写的是“没意识到要先按起点排序没想到用上一个区间的终点做合并判断”。三天后重看这句话整个卡住的场景立刻浮现比重新读一遍解析快得多。Hot 100的题量不需要太庞大的错题本认真记录和复盘一本就够。真正有效的记录是给未来的自己看的所以每一条都尽量让人看得懂当时的困境。4.2 每天的时间分配与节奏参考第10天以后我基本维持了一个很固定的节奏工作日每天投入40分钟左右分成早上25分钟新题和晚上15分钟旧题复盘周末挑一个上午把本周做过的题目不限时地重新手写一遍。这个安排没有多宏大的开始但长期坚持下去效果很好。为什么要分开新旧任务因为新题需要整块的专注时间而旧题复盘的目的是保持熟练度不需要太大脑力放在晚上正好。周末的重新手写则是一个低压力的检验把时间放宽能不能写出来才是关键。我见过不少打卡失败的案例共同特征之一就是第一天用力过猛一上来刷三小时第二天就累了。Hot 100是个持续两个多月的长期任务合理分配体力比追求单日高强度重要得多。4.3 用间隔重复对抗遗忘刷题最大的敌人不是难度是遗忘。一道题当时看懂了觉得自己会了两周后重写发现自己连模板都想不起来这种情况太常见了。我采取的节奏是第1天学完第2天重写一遍第7天再写一遍第14天限时写一遍。用间隔重复代替一次性大量重复记忆留存率高很多。为了配合这个节奏我把每道题都压缩成一张小卡片卡片上只写四个要素题型、触发词、核心模板、复杂度。比如“滑动窗口最长子串/连续区间 - 双指针哈希表 - O(n)/O(n)”。平时翻起来很快面试前也能高频过一遍。卡片的本质是把一道题的解法压缩成可以被快速调用的检索信号真正上考场时大脑需要的不是全文背诵而是快速触发对应的模板。5. 常见问题排查与避坑实录5.1 一道题卡了两个小时死磕还是看答案我的建议是超过20分钟依然没有思路就直接看答案。这不是偷懒而是避免把时间浪费在低效的原地打转上。答案不是用来抄的是用来学习新模板的。看完答案后合上屏幕亲手把代码写出来卡住的地方记进错题本这就算把这题消化了一轮。如何区分“思考”和“空转”思考是有产出的比如你尝试了暴力解法、优化了某个步骤、写了几版思路空转是盯着题目反复看什么都不发生。前者值得继续后者果断切换策略。Hot 100后半段的题目经常会有第一次到第二次“顿悟”的体验但那需要建立在见过足够多模板的基础上看答案本质是在快速增加模板存量。5.2 暴力解能跑但超时优化方向怎么找刷到第10天一定会遇到这么一道题本地测试小数据都正常提交到平台后直接超时。这时候不要着急改局部先看数据规模反推时间复杂度。如果输入长度是10⁴量级O(n²)的算法大概率过不去一旦到了10⁵基本要往O(n log n)或者O(n)想。这个估算能力是刷题前就要建立的能帮你快速排除明显不可行的方案。具体优化方向看题干关键词比死背套路靠谱。出现了“两数之和”“去重”“最近出现”想到哈希表出现“连续子段”“子串”想到前缀和或滑动窗口出现“区间最值”想到单调栈或单调队列出现有序数组查找优先二分。把当天题目记到表格里标注用的是哪一种优化套路一周后回看常见的组合就那么十几种慢慢会形成条件反射。5.3 打卡中断了几天怎么无缝续上打卡中断太正常了。加班、出差、考试、生病都可能让计划断掉。我自己的原则是允许断但不要从零开始。中断后回来不要试图把落下的题一次性补完那样只会让下一次中断的概率更高只做当天的任务先花15分钟复习之前已经做过的题再用30分钟做一道新题找回手感。补打卡的心态也值得警惕。如果强行连续补三天量你会下意识把打卡当成负担而不是能力积累。坦诚地记录“某天未完成”也没什么毕竟表格是用来帮自己成长的不是用来表演完美的。坚持长期主义偶尔的断点不影响整体方向。5.4 刷完一遍Hot 100能到什么水平坦率说完整刷完一遍Hot 100配合每题的复盘和错误记录已经能覆盖大多数技术面试中的算法基础题。因为Hot 100本身就是高频题目的浓缩掌握核心模板后碰到变体题最多需要多花几分钟联想。如果只想达到“面试算法题不慌”的水平这一遍足够了。但如果目标是更强的算法能力比如参加竞赛、应对硬核算法面试一遍远远不够。我的计划是二刷时按题型专题推进不再按清单顺序而是把同一模板的题目集中对比三刷时用随机抽题不挑类型的模式模拟面试现场。到那个阶段Hot 100就不再是任务清单而成了一本属于自己的算法索引。最后再说一个支撑我到第10天的小习惯前一天晚上把第二天要做的题写在一张便签上早上起来打开便签直接开始。这个动作几乎不花时间却帮我省掉了最消耗意志力的“今天做什么”决策。真正能坚持下来的人靠的从来不是每天给自己打鸡血而是把刷题变成一个不需要启动成本的习惯动作。等哪天你不打开记录表也能自然打开清单大概就是这个习惯真正长在身上的时候。Day10只是其中一个小节点往后还有更多题和更多顿悟值得记录这条路我会继续走下去。