题目描述

题目解答
这道题采用双指针的解法,先遍历一边数组,然后在每次循环里新建两个左右指针,之后
通过两个指针逐渐逼近,来寻找唯一的解

java
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
// 结果集:一个"装整数列表的列表",没找到答案时它自然就是空的
List<List<Integer>> result = new ArrayList<>();
// 第一步:排序。
// 作用1:让双指针移动有方向性(偏小左指针右移,偏大右指针左移)
// 作用2:让相同的数相邻,去重才有依据
Arrays.sort(nums);
// 外层循环:枚举三元组中的第一个数 A。
// i 最多到 nums.length - 3,保证 A 后面还至少留两个位置给 B 和 C
for (int i = 0; i < nums.length - 2; i++) {
// 剪枝:数组已排序,nums[0] 是最小值,
// 最小值都大于 0 说明全是正数,不可能凑出 0,直接返回空结果
if (nums[0] > 0) {
return new ArrayList<>();
}
// 对 A 去重:当前数和上一轮的 A 相同,说明这一轮
// 只会重复上一轮的搜索结果(搜索范围还是其子集),整轮跳过。
// i >= 1 的保护条件放左边,保证 i = 0 时不会去访问 nums[-1] 越界
if (i >= 1 && nums[i] == nums[i - 1]) {
continue;
}
// 双指针:left 从 A 的下一个位置出发找 B,right 从末尾出发找 C
int left = i + 1;
int right = nums.length - 1;
while (left < right) {
if (nums[i] + nums[left] + nums[right] < 0) {
// 三数之和偏小:左指针右移,换一个更大的 B 试试
left++;
} else if (nums[i] + nums[left] + nums[right] > 0) {
// 三数之和偏大:右指针左移,换一个更小的 C 试试
right--;
} else {
// 三数之和恰好为 0,收获一组答案
result.add(Arrays.asList(nums[i], nums[left], nums[right]));
// 对 B 去重:下一个 left 的值和当前相同,滑过去不重复计算。
// left < right 防止指针交叉时访问越界
while (left < right && nums[left] == nums[left + 1]) {
left++;
}
// 对 C 去重:同理,跳过右边连续相同的值
while (left < right && nums[right] == nums[right - 1]) {
right--;
}
// 收获答案后两个指针必须一起动:
// 只动一个指针,和就偏离了目标值,找不到新解,
// 遇到重复值时还会收获重复答案
left++;
right--;
}
}
}
return result;
}
}