题目的链接:15. 三数之和 - 力扣(LeetCode)
这道题的意思就是找出给定数组nums中,和为0的三数字组合,之前我们在做两数之和的时候使用了Set的性质来做,但是三个的时候就无法通过一对一的关系找元素了,所以我们要换一种思路来做,从双指针来入手做这个题;
首先我们要明确双指针分别指的是什么,这道题我就直接给出我的思路了,由于是三个数字的组合,假如我们像之前的题目那样,一个指针负责遍历,一个指针负责操作的话那很明显指针是不够用的,但是我们遍历数组又是很有必要的,所以我们两个指针都是用于指向一次遍历中的临时位置的,我们这里规定左指针指向遍历到的当前的位置+1的位置,右指针指向nums的最后一个元素,然后在一次遍历当中我们移动两个指针来实现判断当前位置是否有符合条件的一组数字组合,但是我们如果直接进行判断的话就会造成两个指针的移动需要覆盖所有情况(因为是无序的,所以为了不漏查必须所有组合全判断一遍),最坏的情况下时间复杂度直逼O(n2),所以我们就在处理的最初给nums先排序,使用Java中的Arrays.sort(int nums)排序就行,排序之后就可以简化操作了,可能遇到的情况如下:
(1)当前值+左值+右值==0,加入到结果集中;
(2)当前值+左值+右值>0,由于排好序了所以我们就向左移动右指针;
(3)当前值+左值+右值<0,由于排好序了所以我们就向右移动左指针;
移动指针之后我们为了节省不必要的开销,和防止结果集中出现重复元素,我们可以在移动指针之后进行去重操作,例如我要移动的是左指针,我就搞一个while来对于他右边(下一次要移动的位置)判断是否和当前的值一样,如果一样就在while中给左指针推到最后一个当前值的位置(111最后一个1)再移动指针,这样就可以确保移动之后的值一定指向新的值,得出的三数之和也一定是新值,同时我们也可以对主遍历进行去重,也是和上面一样的道理,其实我们还可以减少开销,就是在每次主遍历开始的时候如果主遍历当前的值>0之后那必然左右指针也大于0,所以也就必然不会出现满足条件的组合了,最后附上我的做法:
java
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
if(nums == null || nums.length == 0){
return res;
}
Arrays.sort(nums);
for(int i = 0;i<nums.length-2;i++){
if(nums[i]>0){
return res;
}
if(i>0&&nums[i]==nums[i-1]){
continue;
}
int left = i+1;
int right = nums.length-1;
while(left < right){
int curSum = nums[left]+nums[right]+nums[i];
if(curSum == 0){
List<Integer> temp = new ArrayList<>();
temp.add(nums[i]);
temp.add(nums[left]);
temp.add(nums[right]);
res.add(temp);
while(left<right&&nums[left]==nums[left+1]){
left++;
}
while(left<right&&nums[right]==nums[right-1]){
right--;
}
left++;
right--;
}else if(curSum < 0){
left++;
}else{
right--;
}
}
}
return res;
}
}