算法中的“记账思维”训练题 2
把“记账思维”练到融会贯通,精选了 10 道覆盖不同算法领域的经典题。它们不再局限于数组,而是延伸到了树、图、字符串、动态规划等领域,但核心都是 “用逻辑账本替代物理操作”。
以下是按难度递增排序的专项训练清单:
1. 难度:简单 (Easy)
题目:268. 丢失的数字 (Missing Number)
- 题目简述:给定一个包含
[0, n]中n个数的数组,找出[0, n]范围内没有出现在数组中的那个数。要求 O(N) 时间,O(1) 空间。 - 为什么契合你的思维:
- 物理直觉:排序后遍历找缺口(O(N log N)),或用哈希表记录出现过的数(O(N) 空间)。
- 记账思维(数学模型替代):把“找缺失值”转化为“总和差值”。完整序列的和是固定的“总账”,减去数组实际元素的和“流水账”,差额就是丢失的数字。完全不需要额外的存储空间来记录状态。
2. 难度:简单 (Easy)
题目:136. 只出现一次的数字 (Single Number)
- 题目简述:非空整数数组中,除了某个元素只出现一次外,其余每个元素均出现两次。找出那个只出现一次的元素。要求 O(N) 时间,O(1) 空间。
- 为什么契合你的思维:
- 物理直觉:用哈希表计数,或排序后两两比较。
- 记账思维(位运算状态压缩):利用异或运算
a ^ a = 0的特性。把所有数字“记”在一个变量里做异或,成对的数字自动抵消(账目清零),最后剩下的就是唯一的那个。这是极致的状态压缩,用一个整数代替了整个哈希表。
3. 难度:中等 (Medium)
题目:560. 和为 K 的子数组 (Subarray Sum Equals K)
- 题目简述:给定一个整数数组和一个整数 k,找出和为 k 的连续子数组个数。
- 为什么契合你的思维:
- 物理直觉:双重循环枚举所有子数组求和(O(N²))。
- 记账思维(前缀和 + 哈希表):把“区间和”转化为“两个前缀和的差”。遍历时记录“当前前缀和”以及“该前缀和出现的次数”(账本)。当发现
当前前缀和 - k在账本中存在时,说明存在若干个子数组满足条件。用一次遍历 + 哈希查找替代了暴力枚举。
4. 难度:中等 (Medium)
题目:198. 打家劫舍 (House Robber)
- 题目简述:相邻房屋不能同时偷,求能偷到的最大金额。
- 为什么契合你的思维:
- 物理直觉:递归尝试所有偷/不偷的组合,指数级复杂度。
- 记账思维(状态机 DP):不模拟“偷窃过程”,而是记录“到第 i 间房时的最优状态”。只用两个变量
rob(偷当前)和not_rob(不偷当前)作为滚动账本,每一步根据上一步的账目更新当前账目。把指数级搜索压缩成了 O(N) 的状态转移。
5. 难度:中等 (Medium)
题目:73. 矩阵置零 (Set Matrix Zeroes)
- 题目简述:若矩阵中某元素为 0,则将其所在行和列全部置 0。要求 O(1) 额外空间。
- 为什么契合你的思维:
- 物理直觉:用两个布尔数组记录哪些行/列需要置零(O(M+N) 空间)。
- 记账思维(原地标记):把矩阵的第一行和第一列当作“行/列账本”。先扫描整个矩阵,遇到 0 就把对应的首行/首列位置标记为 0(记账)。最后根据首行/首列的标记来置零其余部分。用矩阵自身的空间充当了账本,实现了 O(1) 额外空间。
6. 难度:中等 (Medium)
题目:208. 实现 Trie (前缀树)
- 题目简述:设计一个支持插入、搜索、前缀匹配的数据结构。
- 为什么契合你的思维:
- 物理直觉:每次搜索都从头比对字符串,共享前缀被重复处理。
- 记账思维(结构化状态存储):把字符串的“前缀关系”显式地记在树结构中。每个节点代表一个字符,路径本身就是前缀的“账本”。搜索时沿着路径走,无需重复比对已匹配的前缀。把字符串比较问题转化为了树的遍历问题。
7. 难度:中等 (Medium)
题目:347. 前 K 个高频元素 (Top K Frequent Elements)
- 题目简述:找出数组中出现频率最高的 K 个元素。
- 为什么契合你的思维:
- 物理直觉:统计频次后全量排序(O(N log N))。
- 记账思维(桶排序 / 堆):用“频次”作为桶的下标(账本索引),把元素放入对应频次的桶中。然后从高频桶向低频桶取 K 个元素。或者维护一个大小为 K 的最小堆作为“Top-K 账本”,只保留候选者。避免了全量排序,把问题降维到 O(N)。
8. 难度:中等 (Medium)
题目:200. 岛屿数量 (Number of Islands)
- 题目简述:二维网格中,'1' 表示陆地,'0' 表示水,求岛屿数量。
- 为什么契合你的思维:
- 物理直觉:对每个 '1' 做 BFS/DFS 标记,但标记过程可能重复访问或栈溢出。
- 记账思维(并查集 Union-Find):不模拟“淹没/标记”过程,而是把连通性记在并查集中。每个 '1' 初始是一个独立集合,相邻 '1' 合并(union)。最终集合的数量就是岛屿数。把几何连通问题转化为了集合关系的账本维护。
9. 难度:困难 (Hard)
题目:239. 滑动窗口最大值 (Sliding Window Maximum)
- 题目简述:大小为 k 的滑动窗口从左向右移动,返回每个窗口的最大值。
- 为什么契合你的思维:
- 物理直觉:每个窗口内找最大值(O(N*K)),或用堆但删除过期元素麻烦。
- 记账思维(单调队列):维护一个“递减双端队列”作为“候选最大值账本”。新元素入队时,把比它小的队尾元素弹出(因为它们不可能再成为后续窗口的最大值)。队首始终是当前窗口的最大值。用队列的单调性保证了 O(N) 总复杂度,避免了无效比较。
10. 难度:困难 (Hard)
题目:315. 计算右侧小于当前元素的个数 (Count of Smaller Numbers After Self)
- 题目简述:返回数组中每个元素右侧比它小的元素个数。
- 为什么契合你的思维:
- 物理直觉:对每个元素向右遍历计数(O(N²))。
- 记账思维(归并排序 / BIT):在归并排序的合并过程中,“顺便”记录逆序对数量。左半部分的元素被放入结果数组时,右半部分已经放入的元素个数就是“右侧比它小的数量”。把计数操作嵌入到排序的“账本整理”过程中,避免了独立的 O(N²) 统计。或者用树状数组(BIT)把值域映射为索引,通过前缀和查询实现 O(log N) 的单点更新与区间查询。
📌 练习路线建议
| 阶段 | 题目编号 | 核心记账技巧 | 目标 |
|---|---|---|---|
| 入门 | 1, 2 | 数学模型、位运算 | 摆脱哈希表依赖,体会 O(1) 空间的极致压缩 |
| 进阶 | 3, 4, 5 | 前缀和+哈希、状态机DP、原地标记 | 掌握“预处理账本”和“滚动状态”两大范式 |
| 深化 | 6, 7, 8 | 结构化存储、桶/堆、并查集 | 学会将问题转化为特定数据结构的账本维护 |
| 精通 | 9, 10 | 单调队列、排序嵌入计数 | 理解“在操作中顺便记账”的高级延迟计算思想 |
💡 终极心法:每道题做完后,闭上眼睛回顾:“这道题的物理操作是什么?我用什么账本替代了它?账本的 key 和 value 分别代表什么含义?” 当你能脱口而出这些答案时,记账思维就真正长在你脑子里了。

浙公网安备 33010602011771号