LeetCode15
目录
- 题目描述
 - 示例
 - 思路分析
 - 代码段
 - 代码逐行讲解
 - 复杂度分析
 - 总结的知识点
 - 整合
 - 总结
 
题目描述
给你一个整数数组 nums,判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i != j、i != k 且 j != k,同时还满足 nums[i] + nums[j] + nums[k] == 0。请你返回所有和为 0 且不重复的三元组。
注意:
- 答案中不可以包含重复的三元组。
 
示例
示例 1
输入:
nums = [-1, 0, 1, 2, -1, -4]
 
输出:
[[-1, -1, 2],[-1, 0, 1]
]
 
解释:
- 三元组 
[-1, -1, 2]的和为 0。 - 三元组 
[-1, 0, 1]的和为 0。 
示例 2
输入:
nums = [0, 1, 1]
 
输出:
[]
 
解释:
- 唯一可能的三元组 
[0, 1, 1]的和不为 0。 
示例 3
输入:
nums = [0, 0, 0]
 
输出:
[[0, 0, 0]
]
 
解释:
- 唯一可能的三元组 
[0, 0, 0]的和为 0。 
思路分析
问题核心
我们需要找到所有不重复的三元组,使得它们的和为 0。
思路拆解
- 排序: 
- 将数组排序,方便后续的双指针操作。
 
 - 遍历数组: 
- 固定一个数 
nums[i],然后在剩余部分使用双指针寻找两个数nums[left]和nums[right],使得nums[i] + nums[left] + nums[right] == 0。 
 - 固定一个数 
 - 去重: 
- 如果 
nums[i]与前一个数相同,则跳过,避免重复。 - 在找到满足条件的三元组后,跳过重复的 
nums[left]和nums[right]。 
 - 如果 
 - 双指针: 
- 如果 
sum > 0,则右指针左移。 - 如果 
sum < 0,则左指针右移。 - 如果 
sum == 0,则记录结果并移动指针。 
 - 如果 
 
代码段
class Solution {public List<List<Integer>> threeSum(int[] nums) {Arrays.sort(nums);List<List<Integer>> ans = new ArrayList<>();for (int i = 0; i < nums.length; i++) {if (nums[i] > 0) {return ans;}if (i > 0 && nums[i] == nums[i - 1]) {continue;}int left = i + 1;int right = nums.length - 1;while (right > left) {int sum = nums[i] + nums[left] + nums[right];if (sum > 0) {right--;} else if (sum < 0) {left++;} else {ans.add(Arrays.asList(nums[i], nums[left], nums[right]));while (right > left && nums[right] == nums[right - 1]) right--;while (right > left && nums[left] == nums[left + 1]) left++;right--;left++;}}}return ans;}
}
 

代码逐行讲解
-  
排序数组:
- 将数组排序,方便后续的双指针操作。
 
 -  
初始化结果列表:
- 用于存储所有满足条件的三元组。
 
 -  
遍历数组:
- 固定一个数 
nums[i],然后在剩余部分使用双指针寻找两个数nums[left]和nums[right]。 
 - 固定一个数 
 -  
剪枝:
- 如果当前数大于 0,则直接返回结果,因为后续的数都大于 0,无法满足和为 0。
 
 -  
去重:
- 如果当前数与前一个数相同,则跳过,避免重复。
 
 -  
初始化双指针:
left指向i + 1,right指向数组末尾。
 -  
双指针遍历:
- 当右指针大于左指针时,继续遍历。
 
 -  
计算和:
- 计算当前三元组的和。
 
 -  
调整指针:
- 如果 
sum > 0,则右指针左移。 - 如果 
sum < 0,则左指针右移。 - 如果 
sum == 0,则记录结果并跳过重复的nums[left]和nums[right]。 
 - 如果 
 -  
返回结果:
- 返回所有满足条件的三元组。
 
 
复杂度分析
时间复杂度
- 排序的时间复杂度为 O(n log n)。
 - 双指针遍历的时间复杂度为 O(n^2)。
 - 因此,总时间复杂度为 O(n^2)。
 
空间复杂度
- 排序的空间复杂度为 O(log n)。
 - 结果列表的空间复杂度为 O(n^2)。
 
总结的知识点
-  
排序:
- 使用 
Arrays.sort对数组进行排序。 
 - 使用 
 -  
双指针:
- 使用双指针在有序数组中寻找满足条件的两个数。
 
 -  
去重:
- 通过跳过重复的元素,避免生成重复的三元组。
 
 -  
剪枝:
- 通过提前终止循环,减少不必要的计算。
 
 
整合
class Solution {public List<List<Integer>> threeSum(int[] nums) {Arrays.sort(nums);List<List<Integer>> ans = new ArrayList<>();for (int i = 0; i < nums.length; i++) {if (nums[i] > 0) {return ans;}if (i > 0 && nums[i] == nums[i - 1]) {continue;}int left = i + 1;int right = nums.length - 1;while (right > left) {int sum = nums[i] + nums[left] + nums[right];if (sum > 0) {right--;} else if (sum < 0) {left++;} else {ans.add(Arrays.asList(nums[i], nums[left], nums[right]));while (right > left && nums[right] == nums[right - 1]) right--;while (right > left && nums[left] == nums[left + 1]) left++;right--;left++;}}}return ans;}
}
 
总结
通过排序和双指针,能够高效地找到所有和为 0 的三元组。
