问题描述:
// 给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
//
// 注意:答案中不可以包含重复的三元组。
//
// 例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],
//
// 满足要求的三元组集合为:
// [
// [-1, 0, 1],
// [-1, -1, 2]
// ]
//
// 来源:力扣(LeetCode)
// 链接:https://leetcode-cn.com/problems/3sum
// 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解决方案:
对于该问题主要得难点在于去重。
先对该数组原地升序排序。
定义i 为第一个值的下标,left 为第二个值的下标,right为第三个值的下标
i从0到nums.length - 3 依次遍历:
对于每一个i,left初值为i+1,right初值为nums.length - 1
当 left < right时
计算target = nums[i] + nums[left] + nums[right]
当target > 0时说明此时三数之和过大了,right左移
target < 0时,left右移
target == 0说明就是这三个数,但是此时还是不能退出,中间数还是可能存在可行解的。right-- left++
如上只是说了双指针法的大体思路,并未提出去重的解决方案
对于第一个数nums[i],若nums[i] == nums[i - 1],说明这个值之前已经作为第一个数遍历过了 应该跳过这个数,continue即可
对于第二个数nums[left] 若nums[left] == nums[left - 1]同理,跳过这个数即可
第三个数nums[right],若nums[right] == nums[right + 1] 同理
此外由于该数组是排好序的数组,因此dangnums[i] > 0时,意味着i后面的都是大于0的,因此便不存在以nums[i]为第一个数的可行解。整体退出即可。
具体实现代码如下:
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> list = new LinkedList<>();
Arrays.sort(nums);
for (int i = 0; i < nums.length - 2; i++) {
if(nums[i] > 0) {
break;
}
if(i > 0 && nums[i] == nums[i - 1]) {
continue;
}
int left = i + 1;
int right = nums.length - 1;
while(left < right) {
if(left > i + 1 && nums[left] == nums[left - 1]) {
left++;
continue;
}
if(right < nums.length - 1 && nums[right] == nums[right + 1]) {
right--;
continue;
}
int target = nums[i] + nums[left++] + nums[right--];
if (target > 0) {
right--;
} else if(target < 0) {
left++;
} else {
List<Integer> temp = new LinkedList<>();
temp.add(nums[i]); temp.add(nums[left]); temp.add(nums[right]);
list.add(temp);
}
}
}
return list;
}