在 LeetCode 周赛 430 做到 3719 这道题时,我盯着题目标题后面的“I”犹豫了几秒。按 LeetCode 的出题习惯,带“I”的题往往后面还跟着数据范围更大、限制更多的“II”,换句话说这道题多半不是让你一上来就写神仙解法的。我的第一反应也很直白:先写一个接近暴力的版本,跑通思路,拿稳分数,再顺着暴力过程中暴露出来的规律去优化。后来的发展也印证了这个选择,几乎暴力的 O(n^2) 版本能在数据范围内 AC,而从暴力到最终 O(n) 解法之间的那条路,恰恰藏在我自己写的循环里。这篇就完整复盘一下我当时的思考过程,以及这道“最长平衡子数组 I”里最值得沉淀的前缀和与哈希表套路。
1. 我把(几乎)暴力放在第一版,不是摆烂,是周赛策略
很多人在周赛里有一个误区:总觉得不写出最优解就不算做完,于是一上来就死磕 O(n) 或者 O(n log n) 的算法,结果边界条件越调越乱,最后连暴力分都没拿到。我做题的习惯刚好相反,如果肉眼判断数据范围允许,我会先在编辑器里敲一版最简单、最不容易写错的代码,用它来确认自己的理解和测试用例是否正确。
1.1 做题前先花十秒看数据范围
拿到这道题之后,我第一件事不是想数学结论,而是看题目给的约束条件。如果本题的 nums 长度比较小,比如 n ≤ 2000,那么一个 O(n^2) 的枚举方案在 Python 里也只需要百万到千万级别的常数操作,完全可以在 1 到 2 秒内跑完,根本不需要上来就搞什么前缀和哈希表。
这里我通常会做一个快速判断:
- n ≤ 1000:O(n^2) 很稳,O(n^3) 可能有点悬但不一定挂。
- n ≤ 5000:O(n^2) 勉强能过,最好把常数写小一点。
- n ≥ 10^5:O(n^2) 基本没戏,必须想线性或者 O(n log n) 做法。
LeetCode 周赛里的 I 题常见套路是把数据范围控制在中等大小,让不太熟练的人也能用暴力拿到 AC。因此我的结论是:这道题可以先用暴力探路,等理解了问题本质之后再考虑优化。反正暴力代码通常很短,就算最后被淘汰,也能当优化版本的验证器用。
1.2 暴力代码承担的另一层身份:验证器
很多选手没有意识到,暴力代码不只是用来拿保底分的,它还是一个很好的“对拍器”。当你写出 O(n) 的哈希表解法之后,怎么确认自己没有把边界写错?最直接的办法就是生成一组随机测试数据,拿暴力结果跟优化结果对比,一旦不一致,立刻就能定位问题。
我后来写 O(n) 版本的时候,并没有直接删掉暴力代码,而是把它留在一个测试函数里。跑随机数组时,两个版本的结果一直保持一致,我才有信心提交优化版。如果没有暴力版本作为参照,单靠脑补很容易漏掉“前缀和相等但出现在开头”这类边界情况。所以不要瞧不起暴力,它在算法题里的价值比很多人想象中大得多。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
