问题描述
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例:
输入:nums = [-1, 0, 1, 2, -1, -4]
输出:[[-1. -1. 2], [-1, 0, -1]]
约束条件:
- 1.0 <= nums.length <= 3000
- -105 <= nums[i] <= 105
解题思路
问题一:如何去除重复解?
对数组进行排序,每次遍历时,如果和上次遍历的元素相等,则跳过,直到找到和上个元素不相等的元素。这样可以保证,同一个元素在一次遍历中只会选择一次。
问题二:如何遍历元素
首先想到的是暴力法,三层循环,在第三层循环中判断三数之和是否等于 0,若等于 0 则记录并开始下一轮循环;但是此种解法的复杂度为O(n^3),需要寻找更优解。
对于数组的双重循环,我们经常用双指针法的去优化。在此题目中,我们可以将暴力法中第二层和第三层循环转换为双指针方式。即可以将寻找 a + b + c = 0 转换为 寻找 b + c = -a。
算法过程
有长度为 length 的数组 nums,令指针 a 指向下标为 i 的元素,指针 b 指向下标为 i + 1 的元素,指针 c 指向下标为 length - 1 的元素。
- 此时如果 nums[a] + nums[b] + nums[c] = 0, 则找到一组解。然后移动指针 b 和指针 c,继续寻找下一组解。
- 指针 b 向后移动 1。为消除重复值,此时需要判断 nums[b] 和 nums[b - 1] 是否相等,若相等则继续后移,直到移动到 nums[b] 不等于 nums[b - 1] 或者 b >= c。
- 同理,指针 c 向前移动 1。移动后需要判断 nums[c] 和 nums[c + 1] 是否相等,若相等则继续前移,直到 nums[c] 和 nums[c + 1] 不等 或 b >= c。
- 此时如果 nums[a] + nums[b] + nums[c] > 0,即 -nums[a] < nums[b] + nums[c],此时明显 nums[c]的值太大,需要一个更小的值,才有可能使得 nums[b] 和 nums[c] 之和变小,此时,需要将指针 c 向前移动 1。
- 此时如果 nums[a] + nums[b] + nums[c] < 0,即 -nums[a] > nums[b] + nums[c],此时明显 nums[b] 的值比较小,需要一个更大的值,才有可能使得 nums[b] 和 nums[c] 之和变大,此时,需要把指针 b 向后移动 1。
代码
1 | public List<List<Integer>> threeSum(int[] nums) { |