最早看到“耗时100”这个说法,我还以为是100毫秒级别的优化,点进去才发现是LeetCode 1304——Find N Unique Integers Sum up to Zero,也就是“和为零的N个不同整数”这道经典构造题。这道题属于那种一眼看过去很简单、但认真写起来能品出不少东西的题目:给定一个正整数n,要返回一个长度为n的整数数组,数组里所有数字互不相同,并且所有数字的和恰好为0。难度不高,但在刷题指南里经常被归入“脑筋急转弯”或“构造法入门”的范畴,周赛430前后也经常被翻出来当热身题讨论。
我把它当作一个很典型的“构造类问题”来拆解。所谓构造类问题,和一般的“判断类”“搜索类”题目最大的区别在于:它不要求你去找最优解,也不要求你遍历整个解空间,而是要求你快速、稳定地拿出一个满足全部约束的可行解。这类题在面试里出现频率不低,因为能考察你的数学直觉和编码基本功,而不是单纯背模板。
这道题适合刚入门算法的同学,也适合想复盘“构造法”思路的进阶选手。下面从题目定位、思路推导、代码实现到延伸变形,完整展开。
1. 题目定位与核心考点分析
1.1 题面解读:读懂三条硬性约束
先原样看一下这道题的输出要求:给定正整数n,返回长度为n的整数数组,要求数组内n个元素互不相同,且元素总和的值为0。
把这句话拆成三个约束条件来看:
- 长度约束:必须恰好返回n个数,一个不能多,一个不能少。这意味着n为奇数或偶数时,构造方式要有不同的收尾策略。
- 互异约束:数组中任意两个数不能相等。这是很多初学者第一次提交翻车的重灾区——能想到用一对正负数抵消,但没考虑重复。
- 总和约束:这n个数加起来严格等于0。既然目标是0,最自然的思路就是让正数部分和负数部分互相抵消。
题目只要求“返回任意一个满足条件的数组”,不要求数组有序,不要求绝对值最小,也不要求必须包含0。也就是说,可用的解空间非常大。LeetCode上有一类“脑筋急转弯”题,表面是让写算法,实际是让找一个巧妙的构造模式,1304就是这类题里的典型代表。
1.2 为什么这道题是“构造法”入门题
我个人的理解:构造类问题有两条主线,一条是“存在性证明”,一条是“可行性构造”。很多算法题是先从数学上证明某个解一定存在,再想办法把解找出来;而构造类问题通常直接跳过存在性论证,要求你用非常直接的方式把解“搭”出来。
1304之所以适合入门,是因为它把构造思想压缩到一个很简单的场景里:让你在“和为0”和“互不相同”这两条约束下,徒手搭一个数组。你不需要排序、不需要搜索、不需要动态规划,只需要想清楚“一组正负数成对出现就能保证和为0”这个基本事实。把这个事实想明白,剩下的代码只是把数学表达翻译成编程语言。
另外,这道题也是我认为少有的“写完后值得重构两遍”的简单题。第一版用最朴素的循环,第二版用双指针原地填充,第三版用前缀和思想反推端点值。同一个数学构造,三种代码实现,复杂度虽然都是O(n),但你能从中看到不同的编码风格和思考角度。这些角度在后续刷中等难度构造题时非常有用。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 核心思路拆解:从枚举到构造
2.1 三个常见错误方向
先说说我见到过的三种错误做法,把这些坑提前避开。
第一种是回溯搜索。很多人一看到“找到一组解”,就条件反射地想去DFS加剪枝。思路是:从候选整数里选n个,检查是否互不相同且和为0。这个做法在n比较小时确实能跑出来,但随着n变大,状态空间爆炸,效率非常差。题目本身是构造题,不是搜索题,用搜索就是在拿大炮打蚊子,还会因为剪枝条件写不好而陷入超时。
第二种是随机生成加去重。先随机生成n-1个互不相同的数,再算出第n个数为负的总和,然后检查它是否与前面的数冲突,冲突就重来。这个做法能通过测试的概率很高,但存在两个问题:一是你没法证明它在边界情况下
