点赞再看,养成习惯
题目
1. 描述
给你一个整数数组 nums ,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k ,同时还满足 nums[i] + nums[j] + nums[k] == 0 。请你返回所有和为 0 且不重复的三元组。注意:答案中不可以包含重复的三元组。
来源:力扣(LeetCode)
示例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 。
题解
1. 双指针
思路:
- 我们首先可以将数组进行排序,排序后的数组方便我们按照大小逻辑进行计算
- 传统我们暴力破解就是通过三次循环(时间复杂度O(n^3))进行操作,但是此题我们在力扣测试若使用暴力破解会提示超时,因此我们需要想一个办法优化我们的算法。
- 我们可以观察规律,让我们假设三个数分别为
A
,B
,C
,由于我们是一个有序数组,则可以得到一个结论:A<B<C
,这个结论是绝对成立的。 - 根据上述结论我们可以进一步推导若
A>0
,则A+B+C 必定大于0
。 - 若
A<=0
则可以推出0- A =B+C
- 此时如我们第一次遍历数组
for (int i = 0; i < nums.length - 2 && nums[i] < 1; i++)
,此时A = nums[i]
为固定数 ,因此我们只需要寻找剩余的B+C = 0-A
即可。 - 阶段性结论: 刚刚我们推导出
A < B < C
和B+C = 0-A
,此时A为固定数,因此我们只需要通过指针在数组中移动查询B+C = -A
即可。 传统的方式我们采用两层循环,在数组从左到右进行遍历判断,但是这种方式会超出题目要求的运行时间,因此我们需要对这种方式进行优化。 - 重要结论推导: 此时我们假定存在两个指针分别为
leftIndex
及rightIndex
,此时有->nums[leftIndex] = B
,nums[rightIndex] = C
,由于B<C
,且数组有序,因此得到leftIndex
<rightIndex
。 - 因为
leftIndex
<rightIndex
, 因此我们可以控制指针leftIndex 从左到右,rightIndex从右到左进行遍历,此时我们仅需遍历第二次数组即可,无需第三次遍历。
代码:
/*双指针*/
private static List<List<Integer>> threeSum(int[] nums) {
ArrayList<List<Integer>> lists = new ArrayList<>();
/*去重*/
Map<String, Boolean> duplicate = new HashMap<>();
/*第一步 排序*/
Arrays.sort(nums);
for (int i = 0; i < nums.length - 2 && nums[i] < 1; i++) {
Integer leftIndex = i + 1;
Integer rightIndex = nums.length - 1;
while (leftIndex < rightIndex) {
if (nums[i] + nums[rightIndex] + nums[leftIndex] == 0 && duplicate.get("" + nums[i] + nums[rightIndex] + nums[leftIndex]) == null) {
ArrayList<Integer> integers = new ArrayList<>();
integers.add(nums[i]);
integers.add(nums[leftIndex]);
integers.add(nums[rightIndex]);
lists.add(integers);
duplicate.put("" + nums[i] + nums[rightIndex] + nums[leftIndex], true);
leftIndex++;
rightIndex--;
continue;
} else if (nums[i] + nums[rightIndex] + nums[leftIndex] > 0) {
rightIndex--;
continue;
} else {
leftIndex++;
}
}
}
return lists;
}
复杂度分析:
- 时间复杂度:O(N^2)。
- 空间复杂度:O(N)。
运行结果:
结语
今天的内容就到此结束了,有疑问的小伙伴欢迎评论区留言或者私信博主,博主会在第一时间为你解答。
码字不易,感到有收获的小伙伴记得要关注博主一键三连,不要当白嫖怪哦~
如果大家有什么意见和建议请评论区留言或私聊博主,博主会第一时间反馈的哦