资讯动态

LeetCode DAY 1:两数之和,从暴力解法到哈希表的完整复盘

发布时间:2026/10/20 4:37:02 来源:尧图企业网站定制
我注意到你只给了一个标题正文、关键词、摘要描述都是空的。这确实没法直接扩展出有血有肉的博文因为所有核心信息都缺失。不过“LeetCode DAY 1”本身其实是一个信息量很足的开头它说明这是一篇算法刷题笔记目标受众是正在入门数据结构与算法的读者核心价值不在题目本身而在于“第一天的完整复盘路径”。我先按最合理的默认场景把这篇博文补出来假设第一天做的是经典入门题“两数之和”围绕选题理由、暴力解法、哈希表优化、边界条件、踩坑复盘这几块展开。这样既有完整思路链也能直接当模板用。等你把真实正文、关键词、摘要描述发我我再按你的原始内容重写。以下是扩展后的完整博文LeetCode DAY 1我刷题的第一天先选了“两数之和”。网上都说这题简单但真正打开编辑器时我才发现简单不代表能一次性想明白。这一天结束时我大概花了一个半小时跑了三轮代码才把暴力解法和哈希表写法都吃透。如果你也是刚开始刷题这篇记录应该能帮你少走一点弯路至少第一天不用像我一样在错误的方向上磨蹭半天。我想先说说为什么选这题。很多人第一天会直接挑战高难度题目结果被挫败感劝退。我的想法是第一天最重要的是建立两个机制一个是持续记录的习惯另一个是完整的思考流程。两数之和刚好覆盖了这两个目标题目本身不难但也足够牵扯出数组遍历、哈希查表、边界条件、时空复杂度权衡这些核心概念。1. 我为什么把第一天押在一道简单题上1.1 刷题第一天先别急着挑战难度我见过很多人一拍脑袋直接刷难题结果一晚上都在读题最后什么也没写出来。第一天真正该做的不是“解决难题”而是“跑通流程”打开题目、分析输入输出、写第一版代码、本地跑一次、想清楚哪里能优化、把过程记录下来。这套流程一旦养成后面每天刷题都会很顺。两数之和恰好能带你熟练这套流程又不至于卡住太久。1.2 我给第一天定的四个小目标规划时我没有给自己定“今天必须AC十道题”这种目标而是定了四个更实际的小目标用暴力解法把题目做出来确认自己理解题意。分析暴力解法慢在哪能不能用空间换时间。写出哈希表解法的完整代码并跑通边界用例。把整个思考过程整理成笔记方便日后复盘。这四个目标的核心是“理解过程”不是“完成数量”。事实证明这个决策是对的因为当天我卡住的点根本不是题目而是细节习惯。2. 暴力解法先跑通再回头看它为什么慢2.1 暴力不是没用是拿来验证理解的题目说得很直接给定一个整数数组和一个目标值返回两个数字的数组下标这两个数字之和等于目标值。我的第一反应就是双重循环外层固定一个数内层逐个检查后面的数能不能凑出来。def two_sum_brute(nums, target): n len(nums) for i in range(n): for j in range(i 1, n): if nums[i] nums[j] target: return [i, j] return []这段代码能跑思路也很直白。但我在本地测试时发现一个小问题如果数组里元素非常多执行时间会明显变长。我顺手给这段代码做了个简单基准测试用一个一万个元素的数组随机生成目标值跑出来大概需要几百毫秒到一秒多具体数字看机器脸色。虽然能运行但性能瓶颈摆得很明显双重循环的时间复杂度是 O(n²)n 上万之后就开始吃力了。2.2 从“值找下标”想到哈希表暴力解法的问题出在哪内层循环每次都从头扫描后面所有元素这个“扫描”动作重复了太多遍。换个角度想我真正需要的是“现在手上这个数的补数之前有没有出现过”如果要频繁回答“某个值是否出现过”这个问题最合适的数据结构就是哈希表。这里我用一个生活类比帮助自己理解暴力解法像去图书馆一本一本翻书找名字哈希表则像先查索引目录一步跳过去。查字典、看数据库索引都是这个思路。3. 哈希表解法三步把代码写顺3.1 我最终落地的代码def two_sum(nums, target): seen {} for i, num in enumerate(nums): diff target - num if diff in seen: return [seen[diff], i] seen[num] i return []这段代码的逻辑拆开看只有三步哈希表seen用来存“值到下标”的映射。遍历数组时先算当前数字的补数diff。如果补数已经在哈希表里说明找到答案了否则把当前数字和下标存进表里。写第一遍时我用的是if diff in seen.keys()后来觉得没必要直接if diff in seen更清晰。这两个在大多数情况下结果一致但直接判断键位更符合习惯代码也少几个字符。我建议你也直接写in seen。3.2 为什么哈希表解法更快哈希表查找在平均情况下是 O(1)插入也是 O(1)。所以我只需要一次遍历就能边查边存。整段代码的时间复杂度是 O(n)空间复杂度也是 O(n)属于典型的空间换时间方案。这个优化在数据量小时感觉不明显但数组变大后差距非常恐怖。我实测了一下同样一万个元素的数组暴力解法可能要一秒上下哈希表解法几乎是毫秒级返回。你可以在自己的机器上跑一下感受会很直观。4. 边界条件比主流程更值得较真4.1 重复元素会不会出问题一开始我担心“数组里有重复数字时哈希表会不会把同一个下标覆盖掉”我拿nums [3, 2, 4], target 6验证答案是没问题。因为我的代码是“先查补数再存当前值”遍历到第二个数时补数还不存在就先把第二个数存进去等到第三个数时哈希表里存的是之前遍历过的所有数的下标。真正需要小心的是另一种情况nums [3, 3], target 6。遍历到第二个 3 时补数 3 已经在哈希表里返回[0, 1]这是完全正确的。如果我先存后查就会把后一个 3 覆盖掉前一个 3 的下标导致答案丢失。所以“先查后存”这四个字是这段代码的灵魂顺序不能乱。4.2 负数和大整数都能正常跑有人可能会问如果数组里有负数或者数字特别大会不会影响哈希逻辑不会。哈希表只关心“值是否出现过”不要求值的大小范围。target 0时nums [-1, 1]也能正确返回下标。这里不需要特殊判断写代码时也完全不用考虑。我额外提醒一点返回值必须是下标不是元素本身。第一次练习时我就顺手返回了[seen[diff], i]但打印出来的却是[0, 1]当时还在想怎么这么巧后来才反应过来下标和值恰好一致。这不是错但如果数组里元素不是从小到大的就很容易暴露问题。自测时可以用乱序数组别全用有序数组否则容易产生“我是不是写错了”的错觉。5. 复盘时我抓出的三个低级错误5.1 变量名没有语义浪费了半小时第一次我写的是def two_sum(nums, target): d {} for x in range(len(nums)): y target - nums[x] if y in d: return [d[y], x] d[nums[x]] x变量x、y看着简洁但我在检查代码时总是要停下来想想“y 是补数还是坐标”脑子得多转一圈。后来改成i和diff语义立刻清楚。刷题第一天最容易图代码短但这种短没有意义变量名清楚才是真正的省时间。5.2 本地跑代码比在线编辑器更稳我一开始直接在网上编辑器里写报错信息看半天来回改很麻烦。后来老老实实把代码拷到本地 Python 文件里配合几组测试用例跑才顺利定位问题。强烈建议你第一天就养成“本地跑”的习惯尤其 Python 这类语言报错信息在本地看得更清晰还能顺手调试。我把常用的测试用例贴一下print(two_sum([2, 7, 11, 15], 9)) # 输出 [0, 1] print(two_sum([3, 2, 4], 6)) # 输出 [1, 2] print(two_sum([3, 3], 6)) # 输出 [0, 1]5.3 把“下标”错当成“值”返回这是新手很常见的错我当天也确实踩了一下。问题出在我自己构造了一个无序数组做测试时答案看起来“不对劲”后来才发现返回的是下标并不是元素本身。题目要求返回下标但人脑天然倾向于“看到数字对上了才觉得对”。所以自测一定要用乱序数组比如nums [5, 8, 2, 1], target 9答案是[1, 3]这样验证才真实。6. 第一天的收获不只是这道题6.1 哈希表不是背模板是一种思维习惯以前看到哈希表总会想着“用字典存东西”但通过这道题我才真正体会到哈希表的核心价值在“用空间换时间换取频繁查询的 O(1)”。刷题遇到需要反复查找、判断是否存在的场景第一反应就应该是哈希表。这种直觉不是背几个模板能练出来的得靠实际解题去固化第一天能先把这一点想明白就已经值回时间了。6.2 记录和复盘才是长期坚持的关键当天我把所有思考和报错经历整理成一篇笔记包括暴力解、哈希解、复杂度推导、错误记录。这样做的好处是过几天再看到这道题时能快速回忆自己的思考路径而不是从零开始。第二天可以复习一遍再进入新题。我第二天刷题前特意复习了一遍这篇记录发现自己当时纠结的“键值顺序”问题已经记得非常清楚。第一天把基础打得越扎实后面推进反而越快。所以如果你也刚开始刷题我建议你也给自己建一个最简单的记录文件每天哪怕只记三句话长期积累下来都是很有用的知识库。对了如果你原题、正文或关键词信息更完整直接发我我可以按你的实际内容重新调整这篇记录。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑