目录
一:题目链接
题目理解比较简单,需要注意的是最后返回的三元组比如 [-1,0,1] 和 [ 0 , 1 ,-1] 是同一种,应当返回这两其中一个就行。
二:题目思路:
这道题可以利用上我们前面所讲的利用 数组的单调性 + 双指针 的算法思想来解决这问题。

如图,首先,先给数组排个序,让数组呈现单调性,定义起始 i 下标作为固定的数字,我们再定义一个 left 和 right 指针,我们再看题目的一个要求是 nums[i] + nums[j] + nums[k] == 0,也就是说 nums[i] + nums[j] = - nums[k] ,我们就可以把 - nums[k] 当作 i 所指的固定数,那么,题目要求也就变成了 nums[left] + nums[right] = nums[i] 。
在上面的基础上,left 在 i + 1 的位置开始,right 在 .length - 1 的位置开始,在 left 和 right 的区间不断判断 nums[left] + nums[right] = nums[i] 找到符合条件的三元组,其中要注意的是,如果是 nums[left] + nums[right] = nums[i] ,那么后续 letf 和 right 要各自跳过各自指向相同的元素,为什么呢?因为上面说过,“ 比如 [-1,0,1] 和 [ 0 , 1 ,-1] 是同一种,应当返回这两其中一个就行 ”。就以上图的举例,当前三元组可以[ -4 , 0 ,4] 符合条件,然后 left ++ ,right -- ,然后也是[ -4 , 0 ,4 ] ,这就不符合题目要求。
然后再缩小区间继续判断直到当前 left 和 right 相遇结束,我们就解决了固定数字 i 指向的数字的三元组合,后续 i 要继续往后遍历其他的数字,注意,当前固定数字 i 指向的元素也不能重复,也需要跳过当前相同的元素。
三:代码实现
//存储结果集
List<List<Integer>> ret = new ArrayList<>();
//排序数组
Arrays.sort(nums);
int n = nums.length;
for(int i = 0; i < n; ) {
//小优化
if(nums[i] > 0) {
break;
}
int left = i + 1;
int right = n - 1;
int sum = -nums[i];
while(left < right) {
if(nums[left] + nums[right] > sum) {
right--;
}else if(nums[left] + nums[right] < sum) {
left++;
}else {
//添加当前符合条件的三元组
ret.add(Arrays.asList(nums[i],nums[left],nums[right]));
left++;
right--;
//跳过 left 当前相同的元素
while(left < right && nums[left] == nums[left - 1]) {
left++;
}
//跳过 right 当前相同的元素
while(left < right && nums[right] == nums[right + 1]) {
right--;
}
}
}
//处理重复的固定数字
i++;
while(i < n && nums[i] == nums[i - 1]) {
i++;
}
}
//返回结果集
return ret;
小优化那一段代码解释:如果当前 i 指向的元素大于 0 了 ,那么 sum 变量就是负数了 ,后续的 left 和 right 指针一定是在 i 的右边,left + right 指向的元素不可能为负数,就可以直接跳出固定数的循环了。
处理重复的固定数字代码解释: i++ 后,先判断当前 i 的位置,再判断值是否与上一个元素相同。这样就可以避免如果当前 i 已经是越界了再访问数组的情况。
为什么跳过 left 或 right 相同的元素的循环条件有 left < right,是因为避免一种极端情况,比如这样的数组 [0,0,0,0,0,0],如果不加上循环条件 left < right, left 会 不断 ++ 直到越界。
2295

被折叠的 条评论
为什么被折叠?



