两数之和 ACM 版
把两数之和改成标准输入输出,重点练哈希表存已访问数字。
题单
每道题都能跳到图解动画,也能进入 OJ 直接提交;补满 100 道后仍按这套专题结构承载。
先练数组扫描、频次统计、前缀和与哈希表,把最常用的数据组织方式跑顺。
把两数之和改成标准输入输出,重点练哈希表存已访问数字。
候选人抵消模型,练习 O(1) 空间的多数元素查找。
统计前缀和出现次数,边扫边找 prefix - k。
把排序后的字符串作为 key,把同组单词收集到一起。
用哈希集合判断序列起点,只从最小起点向后延伸。
按左端点排序后维护当前合并区间的右边界。
把 k 对 n 取模后,用切片或三次翻转完成右轮转。
先乘左侧前缀,再从右向左累乘右侧后缀。
利用 x ^ x = 0 和 x ^ 0 = x,把所有数异或起来。
用三指针把 0 放左边、2 放右边,1 留在中间。
从右找第一个下降点,交换后把后缀反转成最小序。
把数组值看作指针走向,用环入口定位重复数字。
用 Map 维护访问顺序,淘汰最久未使用的键。
从左维护最大值、从右维护最小值,定位需要排序的左右边界。
围绕左右边界、快慢指针和窗口收缩,训练一次遍历里的不变量。
用左右指针维护一个没有重复字符的窗口。
每次移动较短的板,练习双指针的不变量。
排序后固定第一个数,再用左右指针去重枚举。
慢指针指向下一个非零元素应该放的位置。
窗口和达到 target 后尽量收缩左边界。
双指针维护左右最高墙,每次结算较矮一侧能接的水。
枚举每个中心向两边扩展,长度相同取更靠左的答案。
维护长度为 p 的窗口计数,计数一致时记录左端点。
右指针扩张满足需求后,左指针尽量收缩窗口。
练二维数组的行列标记、边界收缩、原地旋转和有序矩阵搜索。
覆盖排列、组合、子集、括号生成和网格搜索,重点练选择、撤销与剪枝。
按数字对应字符集逐层回溯,生成所有组合。
只在左括号数量不超 n、右括号不超左括号时继续搜索。
排序后从当前下标继续选择,允许重复使用同一个数字。
用 used 数组标记已选择元素,逐层构造排列。
每个位置都有选或不选两种选择,按递归顺序收集子集。
从每个格子作为起点做 DFS,同一路径中不能重复使用格子。
把指针顺序、合并、反转和环形关系看清楚,再用 ACM 输入输出稳定复现。
用两个指针顺序归并两个升序序列。
用 prev、cur、next 三个指针保护链表不断链。
用数组模拟逆序链表,逐位相加并处理进位。
用快慢指针找到倒数第 n 个节点的前驱,再删除目标节点。
快指针一次走两步、慢指针一次走一步,相遇则有环。
ACM 版用数组模拟链表,重点核对归并排序后的有序结果。
两指针分别走完 A+B 与 B+A,相遇点就是交点。
找到中点后反转后半段,再与前半段逐个比较。
练括号匹配、单调结构、Top K 和队列窗口,把进出顺序与候选维护想明白。
遇到左括号入栈,遇到右括号检查栈顶。
先计数,再按频率降序和数值升序输出前 K 个。
栈里保存还没找到更高温度的下标。
把每个链表当前元素放入小根堆,持续弹出最小值。
主栈存值,辅助栈同步存当前最小值。
队列中维护下标,保证对应值递减,队首就是窗口最大值。
遇到左括号入栈保存当前串和重复次数,右括号时展开。
单调递增栈中保存下标,弹栈时用当前下标确定右边界。
从层序遍历开始建立树题手感,再逐步进入递归、路径和树形 DP。
用队列逐层扩展节点,练习树的层序输出。
递归或栈模拟左根右顺序。
中序遍历必须严格递增,或递归维护上下界。
同时比较左子树的左/右与右子树的右/左。
最大深度等于左右子树最大深度加一。
前序首元素是根,在中序中切分左右子树递归构造。
按先序遍历顺序把节点接到右指针链上。
后序返回单边最大贡献,同时用左右贡献更新全局答案。
递归交换每个节点的左右子树。
后序递归,若左右子树分别找到目标,则当前节点就是 LCA。
每个节点返回偷当前节点和不偷当前节点两种收益。
DFS 时维护从根到当前节点的前缀和计数。
每个节点用左右子树深度之和更新最长路径边数。
两个节点都存在时相加,否则保留存在的一侧。
层序遍历时记录每一层最后一个节点。
BST 的中序遍历是升序,第 k 个访问到的节点就是答案。
覆盖网格搜索、拓扑排序、并查集、最短路和多源 BFS,重点练建图与访问状态。
从未访问过的陆地出发,把同一连通块全部染色。
用入度和队列判断有向图是否存在环。
把相连城市合并,最后统计连通块数量。
从每个未访问陆地出发扩展,统计连通块面积。
把所有腐烂橘子同时入队,按层模拟分钟流逝。
从源点跑 Dijkstra,取所有最短距离的最大值。
把边界、单调性和答案空间拆开练,避免只会套模板。
二分吃香蕉速度,检查总耗时是否不超过 h。
找第一个大于等于 target 的位置,就是插入位置。
把矩阵看成一条升序数组,对虚拟下标做二分。
分别找第一个大于等于 target 和第一个大于 target 的位置。
每次判断哪一半有序,再决定 target 落在哪一侧。
用右端点判断最小值在左半还是右半。
在较短数组上二分切分位置,让左右两侧数量和大小关系都成立。
从一维 DP、网格 DP、背包和股票状态机,过渡到能说清状态与转移。
维护以当前位置结尾的最大连续和。
把最后一步拆成迈 1 阶或 2 阶,得到斐波那契式转移。
一边扫价格,一边记录历史最低买入价。
每个位置只在抢和不抢之间做选择。
维护每个长度的最小结尾值,练习贪心加二分。
把金额当作状态,枚举最后使用的硬币。
维护当前能到达的最远位置,判断是否覆盖最后一个下标。
按层扩展当前跳跃范围,每到边界就增加一次跳跃。
每个格子的路径数等于上方和左方路径数之和。
原地或滚动数组维护从左上角走到每个格子的最小代价。
dp[i] 表示前 i 个字符能否由词典拼出。
把问题转成是否能凑出 sum / 2。
先枚举硬币,再枚举金额,统计组合数而不是排列数。
同时维护以当前位置结尾的最大乘积和最小乘积。
dp[i][j] 表示以当前位置为右下角的最大全 1 正方形边长。
环形房屋拆成不偷首家和不偷末家两种线性情况。
维护持有股票和不持有股票两个状态。
卖出后第二天不能买入,需要把冷冻状态纳入转移。
dp[i][j] 表示两个前缀的最长公共子序列长度。
把平方数当作物品,做最少个数的完全背包 DP。
用最高频任务构造空槽,答案取公式值和任务总数的最大值。
每段右边界取段内字符最后出现位置的最大值。