BM54 三数之和¶
中等通过率 22.68%python3核心代码模式样例通过牛客 AC数组排序双指针
讲解章节:双指针与滑动窗口
一句话
排序后固定最小的数,另外两个用左右双指针夹逼,三处跳重。
解题思路¶
这题考什么¶
排序是这题的总开关,一次排序同时解决三件事:三元组内部自动非降序、 相同元素挨在一起便于跳过、有序数组才能用双指针单调夹逼。
主体是「固定一个 + 双指针」:
for i in 0 .. n-3: 固定最小的数 num[i]
left = i + 1, right = n - 1
while left < right:
s = num[i] + num[left] + num[right]
s == 0 记账,然后两个指针同时内移并跳过重复
s < 0 和偏小,只能把小的一端抬高 -> left 加一
s > 0 和偏大,只能把大的一端压低 -> right 减一
双指针不会漏解:数组有序,s < 0 时把 right 左移只会让和更小, 那一列组合整体可以安全排除;s > 0 对称。每轮至少有一个指针移动, 内层是 O(n),配上外层的 O(n) 共 O(n 的平方)。 双指针的通用套路见 双指针与滑动窗口。
数据规模与复杂度¶
0 <= n <= 1000,元素取值 |val| <= 100,时限其他语言 2 秒。 排序 O(n log n) 加主体 O(n 的平方) = 1e6 次基本操作,Python 下零点几秒。 三重循环枚举是 1e9 次,判题机比本机还慢数倍,必然超时。 空间:sorted 另建一份长度 n 的列表,O(n),题面允许到 O(n 的平方)。
坑在哪¶
- 三元组内部必须非降序(题面注意事项第一条 a <= b <= c)。 排序后按 i < left < right 取值天然满足;换成哈希凑数的写法还得对每组结果 单独排序,且去重更难写。
- 三处跳重缺一不可,牛客严格比对,多出一份重复三元组就是错: 外层不跳,[0,0,0,0] 会输出两份 [0,0,0]; 命中后不跳 left 与 right,[-2,0,0,2,2] 会把 [-2,0,2] 输出两次。
- 命中后两个指针必须同时移动。只移一个的话,和必然偏离 0, 虽不至于出错但白跑一轮;两个都不动就是死循环。
- 剪枝用 break 而不是 continue:排序后 num[i] > 0 意味着后面的 i 只会更大, 三个正数的和不可能为 0,整个外层可以直接结束。
- 解集本身的顺序也参与比对。外层 i 递增、内层 left 递增,产出的结果集 恰好是字典序升序,不需要也不应该再排一次。
- n < 3 时 range(n - 2) 为空(n = 0 时是 range(-2),同样为空), 直接返回空列表,示例 1 的 [0] 正是这种输入。
样例复核¶
[-10, 0, 10, 20, -10, -40],排序后 [-40, -10, -10, 0, 10, 20]。
输出 [[-10,-10,20], [-10,0,10]],与题面给出的解集一致。
参考实现¶
[:octicons-arrow-left-16: BM53](BM53.md) [BM55 :octicons-arrow-right-16:](BM55.md)