15. 三数之和
题目: 给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。
注意: 答案中不可以包含重复的三元组。
思路: 采用 排序 + 双指针。
核心思想:
先排序,固定一个数,再用左右指针寻找另外两个数,使三数之和为 0。
具体过程:
-
先对数组排序,并跳过重复的
nums[i]。 -
固定
nums[i],设置j=i+1、k=n-1。 -
如果三数之和大于
0,k--;小于0,j++。 -
等于
0时加入答案,并跳过重复元素。
时间复杂度:O(n²)
空间复杂度:O( log n)(排序所需)
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> ans = new ArrayList<>();
int n = nums.length;
for (int i = 0; i < n - 2; i++) {
int x = nums[i];
if (i > 0 && x == nums[i - 1]) continue; // 跳过重复数字
if (x + nums[i + 1] + nums[i + 2] > 0) break; // 优化一
if (x + nums[n - 2] + nums[n - 1] < 0) continue; // 优化二
int j = i + 1;
int k = n - 1;
while (j < k) {
int s = x + nums[j] + nums[k];
if (s > 0) {
k--;
} else if (s < 0) {
j++;
} else { // 三数之和为 0
ans.add(List.of(x, nums[j], nums[k]));
for (j++; j < k && nums[j] == nums[j - 1]; j++); // 跳过重复数字
for (k--; k > j && nums[k] == nums[k + 1]; k--); // 跳过重复数字
}
}
}
return ans;
}
}