题目
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
思路
- 首先想到的就是遍历,三重遍历暴力求解不太靠谱,时间复杂度是O( n 3 n^3 n3).很暴力。
- 两数之和双指针的做法:在一个有序数列,若找两数之和为0,用序列中最大(最左边)和最小(最右边)相加,小于0需要增大两数,左指针右移增大,大于0则需要减小两数,右指针左移减小,遇到等于0记录下来就好了。
- 遇到这种题排序为有序序列为常规操作,这一题就排序先固定一个值,然后在剩下的序列中用2的做法即可
- 测试用例出现了重复元组,要在固定k和移动指针时去掉重复元素
代码
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List< List< Integer>> res = new ArrayList<>();
if(nums.length < 3 || nums == null) return res;
int i = 0, n = nums.length;
Arrays.sort(nums);
for(; i < n; ++i)
{
int k = nums[i];
if(i-1 >= 0 && k == nums[i-1]) continue;
int left = i + 1, right = n-1;
while(left<right){
int s = k + nums[left] + nums[right];
if(s == 0){
res.add(Arrays.asList(k, nums[left], nums[right]));
//去掉重复值
while(left < right && nums[left] == nums[++left]);
while(left < right && nums[right] == nums[--right]);
}else if(s>0){
//需要减少
while(left < right && nums[right] == nums[--right]);
}else while(left < right && nums[left] == nums[++left]);
}
}
return res;
}
}
时间复杂度:排序的时间复杂度为O(nlogn),排序后的遍历为O( n 2 n^2 n2).所以时间复杂度为O( n 2 n^2 n2).