文章目录
一、题目描述
题目地址:LeetCode - 3Sum
给定一个长度为 n 的整数数组 nums,要求找出所有 唯一的三元组 [nums[i], nums[j], nums[k]],使得:
nums[i] + nums[j] + nums[k] == 0
并且:
i != j, j != k, i != k
返回所有不重复的三元组。
示例:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
二、问题分析
本题的目标是从数组中找出所有三个数相加为 0 的组合。
关键挑战:
- 要确保三元组不重复(即
[a,b,c]和[b,a,c]要被视为相同)。 - 需要高效地搜索组合,不能使用简单的三重循环暴力法(O(n³))。
三、思路图解
我们可以将问题的思路用一个流程图展示:
是
小于0
大于0
输入数组 nums
排序 nums
固定第一个数 i: nums[i]
使用双指针 left、right 搜索剩余两个数
nums[i] + nums[left] + nums[right] == 0?
记录三元组并移动指针去重
left++ 增大和
right-- 减小和
返回所有不重复的结果
该算法的核心是:
- 排序;
- 固定一个数,用双指针解决两数之和问题;
- 去重。
四、几种解法比较
1. 暴力三重循环法
思路:
遍历所有三元组组合并判断和是否为 0。
缺点:
- 时间复杂度 O(n³)
- 大量重复组合,需要去重处理。
复杂度:
- 时间:O(n³)
- 空间:O(n)
2. 排序 + 双指针法(推荐解法)
核心思想:
- 先排序。
- 遍历每个数,固定为第一个数
nums[i]。 - 在
[i+1, end]范围内用左右指针寻找另外两个数,使三者之和为 0。 - 使用去重逻辑避免重复三元组。
算法步骤示意图:
是
< 0
> 0 排序数组
固定 nums[i]
left 指向 i+1, right 指向末尾
计算 sum = nums[i]+nums[left]+nums[right]
sum == 0?
加入结果并移动 left/right 去重
left++
right--
复杂度分析:
- 时间复杂度:O(n²)
- 空间复杂度:O(1)(不计结果存储)
3. 哈希辅助法(改进版本)
思路:
- 固定一个数
nums[i],然后用 HashSet 查找是否存在-nums[i] = nums[j] + nums[k]。 - 相对双指针法,不如排序法直观,且去重复杂。
复杂度:
- 时间:O(n²)
- 空间:O(n)
五、详细复杂度分析
| 解法 | 时间复杂度 | 空间复杂度 | 是否易去重 | 是否推荐 |
|---|---|---|---|---|
| 暴力法 | O(n³) | O(n) | 否 | 否 |
| 排序+双指针 | O(n²) | O(1) | 是 | ✅ 推荐 |
| 哈希辅助 | O(n²) | O(n) | 较复杂 | 可考虑 |
六、Java代码实现(排序 + 双指针)
java
import java.util.*;
public class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums); // 先排序
int n = nums.length;
for (int i = 0; i < n; i++) {
// 去重:当 nums[i] == nums[i-1] 时跳过
if (i > 0 && nums[i] == nums[i - 1]) continue;
int left = i + 1;
int right = n - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum == 0) {
res.add(Arrays.asList(nums[i], nums[left], nums[right]));
// 移动指针去重
while (left < right && nums[left] == nums[left + 1]) left++;
while (left < right && nums[right] == nums[right - 1]) right--;
left++;
right--;
} else if (sum < 0) {
left++;
} else {
right--;
}
}
}
return res;
}
}
总结
| 关键策略 | 说明 |
|---|---|
| 排序 | 有助于快速去重与双指针搜索 |
| 双指针 | 在 O(n²) 时间内实现两数和目标 |
| 去重 | 三种情况:固定数去重、左指针去重、右指针去重 |
本题是二维双指针的经典应用,也是理解 "两数之和" 到 "三数之和" 的自然延伸。