---
title: 轻松掌握 LeetCode 经典算法题「三数之和」：利用数组排序与双指针技巧高效找出所有零和三元组的详细教程
created: 2026-03-10
updated: 2026-03-10
type: summary
tags: ["algorithm", "notes", "pointers", "sorting", "telegram"]
external: http://go/ui/posts/2139/
---

好的，我们一起来解决 LeetCode 上的「三数之和」问题。我会用最简单的方式解释给你听，就像在给初中生讲数学题一样。

## 问题是什么？

给你一个整数数组，比如 `[-1, 0, 1, 2, -1, -4]`，你要找出所有 **三个数加起来等于 0** 的组合，而且这些组合不能重复。

举个例子：
- 找到 `-1 + 0 + 1 = 0`，所以 `[-1, 0, 1]` 是一个答案。
- 找到 `-1 + -1 + 2 = 0`，所以 `[-1, -1, 2]` 也是一个答案。
- 注意 `[0, 1, -1]` 其实和第一个一样，只是顺序不同，我们不要重复的。

所以最终答案应该是：`[[-1, -1, 2], [-1, 0, 1]]`。

## 怎么解决？

一个直接的想法：用三个循环枚举所有可能的三元组，检查是否和为0，再去重。但这样太慢了，数组一大就超时。

我们需要更聪明的方法，这里介绍 **排序 + 双指针** 的方法，就像玩一个找数字的游戏。

### 第一步：排序

先把数组从小到大排序，像排队一样排好。比如上面的数组排序后变成：`[-4, -1, -1, 0, 1, 2]`。

排序的好处是：
- 相同的数字会挨在一起，方便我们跳过重复。
- 我们可以用两个指针从两边向中间移动，快速找到需要的组合。

### 第二步：固定一个数，然后用双指针找另外两个

我们想象一下：要找到三个数 a + b + c = 0，相当于固定 a，然后找 b + c = -a。

我们从头开始，把每个数字当作 a（但要注意跳过重复的 a）。对于每个 a，我们用两个指针：一个指向 a 后面最小的数（左指针），一个指向数组末尾最大的数（右指针）。

然后看 `左指针的数 + 右指针的数` 是不是等于 `-a`：
- 如果等于，就找到了一个组合，记录下来，然后左指针右移、右指针左移（同时跳过重复的数）。
- 如果小于 `-a`，说明和太小了，需要更大的数，所以左指针右移。
- 如果大于 `-a`，说明和太大了，需要更小的数，所以右指针左移。

这样一直移动直到两个指针相遇，就完成了这个 a 的查找。

### 第三步：避免重复

- 当 a 和前一个数一样时，跳过，避免重复的三元组。
- 当左指针移动时，如果下一个数和当前一样，也要跳过。
- 右指针同理。

## 代码实现（Python）

下面就是完整的代码，每行都有注释，方便你理解：

```python
def threeSum(nums):
    # 先对数组排序
    nums.sort()
    res = []  # 存放结果
    n = len(nums)

    # 固定第一个数 a
    for i in range(n - 2):
        # 如果当前数字和前一个相同，跳过（避免重复）
        if i > 0 and nums[i] == nums[i - 1]:
            continue

        # 双指针初始化
        left = i + 1
        right = n - 1
        target = -nums[i]  # 需要 b + c = -a

        while left < right:
            s = nums[left] + nums[right]
            if s == target:
                # 找到一个组合
                res.append([nums[i], nums[left], nums[right]])
                # 移动左指针，跳过重复
                left += 1
                while left < right and nums[left] == nums[left - 1]:
                    left += 1
                # 移动右指针，跳过重复
                right -= 1
                while left < right and nums[right] == nums[right + 1]:
                    right -= 1
            elif s < target:
                # 和太小，左指针右移
                left += 1
            else:
                # 和太大，右指针左移
                right -= 1

    return res

# 测试一下
nums = [-1, 0, 1, 2, -1, -4]
print(threeSum(nums))  # 输出 [[-1, -1, 2], [-1, 0, 1]]
```

## 总结

- 先排序，让数组有序。
- 固定一个数，然后用双指针找另外两个数。
- 注意跳过重复的数，避免答案重复。

这样我们就能高效地找到所有不重复的三元组了。如果你有哪里不明白，随时问我！
