#15
Medium
双指针

3Sum

返回所有和为 0 的不重复三元组。

返回所有和为 0 的不重复三元组。真正的模式是先排序,再把内层搜索变成双指针扫描。

ArrayTwo Pointers

题目定位

排序之后,内层 pair 搜索就能变成可控的双指针扫描,而外层循环只负责固定一个数。

关键观察

数组有序后,剩余两个数的移动方向完全由当前和偏小还是偏大决定。

目标复杂度

O(n^2) / O(1)

这题的解法思路怎么拆

1

先排序,这样去重和指针移动都会变得可控。

2

固定下标 i 处的数字,把问题转成后缀区间上的 two-sum。

3

用左右指针搜索剩下两个数。

4

外层循环和内层指针都要跳过重复值。

拿一个例子顺一遍

1

例如 [-1, 0, 1, 2, -1, -4] 排序后变成 [-4, -1, -1, 0, 1, 2]。

2

固定 index 1 的 -1,再在后缀里用 left = 2、right = 5 做双指针搜索。

3

可以找到 [-1, -1, 2] 和 [-1, 0, 1],并在移动时顺手跳过重复值。

4

后面的 anchor 不会再产生新的不重复三元组。

参考实现

Python
def threeSum(nums: list[int]) -> list[list[int]]:
    nums.sort()
    answer: list[list[int]] = []

    for index in range(len(nums) - 2):
        if index > 0 and nums[index] == nums[index - 1]:
            continue

        left, right = index + 1, len(nums) - 1
        while left < right:
            total = nums[index] + nums[left] + nums[right]
            if total == 0:
                answer.append([nums[index], nums[left], nums[right]])
                left += 1
                right -= 1
                while left < right and nums[left] == nums[left - 1]:
                    left += 1
                while left < right and nums[right] == nums[right + 1]:
                    right -= 1
            elif total < 0:
                left += 1
            else:
                right -= 1

    return answer

常见坑点

warning

外层或内层忘记跳过重复值。

warning

没先排序,导致指针移动失去依据。

高频追问

如果目标值变成任意 k,结构如何复用?

重复值到底该在哪几步跳过,为什么?

继续刷相关题

先把 双指针 这个模式刷成体系,再去做更难变体。

view_week回到模式页
LeetCode 15. 3Sum 题解思路 | Interview AiBox