小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
题目
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
来源:力扣(LeetCode)
思路
1.暴力解法,for循环三层遍历+哈希表去重时间复杂度O(N)
2.首先考虑怎么去重复的问题,设第一重循环的数为a,第二重循环的数为b,第三重循环的数为c, 那么只需要保证a<=b<=c这样就可以,那么假如有两个相同的数会被第一重循环使用两次呢,那么我们只需要加一个这样的判断,同样的第二重循环第三重循环也可以这样写。
if (first != 0 && nums[first] == nums[first - 1]) continue;
3.但是问题来了,这样写虽然省去了使用哈希表去重的空间但是依然要使用三重循环时间复杂度为O(N^3),此时的想法是固定a,那么当b+c满足b+c=-a时就可以和a组成一个答案,这就转换成了数组中求和为target的问题(双指针,一个头开始一个尾开始),此时bc就是在一层循环里面了因此总的时间复杂度为O(N^2)
4.当然完成3的前提是先排序
代码
public class Code05_ThreeSum {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums); //从小到大排序
List<List<Integer>> ans = new ArrayList<>();
for (int first = 0; first < nums.length; first++) {
//对于first去重
if (first != 0 && nums[first] == nums[first - 1]) continue;
int target = -nums[first];
int third = nums.length - 1;
for (int second = first + 1; second < nums.length; second++) {
//对于second去重
if (second != first + 1 && nums[second - 1] == nums[second]) continue;
while (second < third && nums[second] + nums[third] > target) {
third--;
}
if (second == third) break; //注意这边值的不是值相同而是指向同一个数的意思
if (nums[second] + nums[third] == target) { //满足条件添加到ans
List<Integer> curList = new ArrayList<>();
curList.add(nums[first]);
curList.add(nums[second]);
curList.add(nums[third]);
ans.add(curList);
}
}
}
return ans;
}
}