给你一个整数数组 nums
,判断是否存在三元组 [nums[i], nums[j], nums[k]]
满足 i != j
、i != k
且 j != k
,同时还满足 nums[i] + nums[j] + nums[k] == 0
。请你返回所有和为 0
且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4] 输出:[[-1,-1,2],[-1,0,1]] 解释: nums[0] + nums[1] + nums[2] = (-1) + 0 + 1 = 0 。 nums[1] + nums[2] + nums[4] = 0 + 1 + (-1) = 0 。 nums[0] + nums[3] + nums[4] = (-1) + 2 + (-1) = 0 。 不同的三元组是 [-1,0,1] 和 [-1,-1,2] 。 注意,输出的顺序和三元组的顺序并不重要。
示例 2:
输入:nums = [0,1,1] 输出:[] 解释:唯一可能的三元组和不为 0 。
示例 3:
输入:nums = [0,0,0] 输出:[[0,0,0]] 解释:唯一可能的三元组和为 0 。
提示:
-
3 <= nums.length <= 3000
-
-105 <= nums[i] <= 105
思路:
这道题首先限制了三个元素的位置不能相同,并且不能包含数相同但顺序不同的三元组,如[-1,0,1]与[0,-1,1]算作是相同的元素。因为顺序并不作为限制因素,数组原是无序的,对数据的查找有很大的影响,故第一步要先进行排序。
该题就变成了一个三指针移动问题,固定begin,移动mid和end来找到和为零的数。那么我们应该如何来移动mid和end呢?假设begin+mid+end=0,那么应该如何移动mid和end呢? mid动了end要已一起动才能保证和是不变的,因为两个指针要保证一个增大一个减小才会有可能使和保持不变,即mid++;end--;。假设begin+mid+end<0,就证明现在总和要增大,就会向右移动mid,即mid++;反之如果begin+mid+end>0,就要向左移动end来减小总和,即end--。
如何移动指针这个问题我们搞定了,现在还会存在一个问题,就是我们移动这三个指针的时候,下一个元素可能是重复元素,因此还要判断移动指针后的元素遇上一个元素是否相同。
//IDEA测试代码
public static void main(String[] args) {
int[] h = {0,0,0};
List<List<Integer>> l = threeSum(h);
System.out.println(l);
}
public static List<List<Integer>> threeSum(int[] nums) {
//对数组进行排序
int[] arr = nums;
Arrays.sort(arr);
//用来接收返回值
List<List<Integer>> lists = new ArrayList<>();
for (int begin = 0; begin < arr.length - 1; begin++) {
//end要保证总最后开始,双指针的规则就是两头向中间挤
int end = arr.length - 1;
//首先防止begin指针与前一个元素相同
if (begin > 0 && (arr[begin] == arr[begin - 1])) continue;
for (int mid = begin + 1; mid < arr.length - 1; ) {
//设置停止条件
if (mid >= end) break;
//首先防止mid指针与前一个元素相同
if (mid > begin + 1 && (arr[mid] == arr[mid - 1])) {mid++;continue;}
//我这里忘记对end指针进行重复移动了
if ((arr[begin] + arr[mid] + arr[end]) > 0) end--;
else if ((arr[begin] + arr[mid] + arr[end]) < 0) mid++;
else {
List<Integer> list = new ArrayList<>();
list.add(arr[begin]);
list.add(arr[mid]);
list.add(arr[end]);
lists.add(list);
//双向移动指针
mid++;
end--;
}
}
}
return lists;
}
总结:
这道题是一道双指针移动的一个变型,对于指针的移动主要还是考虑不要使用重复元素,个人认为使用set对数组进行一个去重然后操作双数组,应该也是可以解决的,本质上使用空间换时间。