LeetCode15三数之和
题目:
思路:
虽然上一种做法有问题,不过双指针的想法还是正确的。所以,应该换个思路。
先对列表进行排序,然后从头到尾遍历。这样每次都固定住一个值,而不是用双指针来解决三值问题,好像是可行的。
在固定一个值之后,剩下的有序列表中,用双指针法寻找两个值的和是否是固定值的负数。这样指针移动的标准也就出来了。如下图:
当两值之和大于固定值的负数时,右边的指针左移
当两值之和小于固定值的负数时,左边指针右移
当两值之和恰好为固定值负数,保存结果。此时有个很有必要的操作:判断 start+1的值,end-1的值,是否与上一个一样,相同的话,则跳过处理,我一开始就没处理,想偷懒最后保存结果的时候去重即可,但是去重要使用in方法,O(n)O(n)的复杂度,增加了时间复杂性。
解题步骤:
难点1:时间;难点2:重复元素。
- 1.数组排序。
- 2.设置固定点,前指针和后指针。
- 每一次固定点不动,前指针后移,后指针前移,三数之和为0,即为需要找的元素。
- 前后指针之和大于固定点,后指针前移(因为已排序)
- 同理,处理小于情况。
- (以上都为节省时间服务)
- 每一次指针移动都要提前判断后面的值是否与当前指针元素相同,避免向集合加入相同元素。
代码:
public class Solution {
public List<List<Integer>> threeSum(int[] nums){
List<List<Integer>> list = new ArrayList<>();
if (nums == null || nums.length<3){
return list;
}
int length = nums.length;
int fix = 0;//固定点
int start ;//前指针
int end ;//后指针
Arrays.sort(nums);//原数组排序
for (int i = fix; i < length-2; i++) {//-2原因:不能包括前后指针
if(i == 0 ||(i > 0 && nums[i] != nums[i-1]) ){//去重
start = i + 1;
end = length -1;
while (start<end){
if (nums[start] + nums[end] == -nums[i]){
list.add(Arrays.asList(nums[start],nums[end],nums[i]));
while (start<end && nums[start] == nums[start + 1]){start++;}//去重
while (start<end && nums[end] == nums[end - 1]){end--;}//去重
start++;
end--;
}else if (nums[start] + nums[end] > -nums[i]){
while (start<end && nums[end] == nums[end - 1]){end--;}//去重
end--;
}else if (nums[start] + nums[end] < -nums[i]){
while (start<end && nums[start] == nums[start + 1]){start++;}//去重
start++;
}
}
}
}
return list;
}
}