1. 题目
给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2. 思路
首先对数组进行排序
,排序后固定最左面的数 nums[left]
,再使用中右指针指向 nums[left]
后面的两端,数字分别为 nums[mid]
和 nums[right]
,计算三个数的和 sum
判断是否满足为 0
,满足则添加进结果集
如果 nums[left]
大于 0
,则三数之和必然无法等于 0
,结束循环
如果 sum > 0
应减小 right
, 反之增大 mid
如果 nums[left++] == nums[left]
,则说明该数字重复,会导致结果重复,所以应该跳过
如果 nums[right--] == nums[right]
或者nums[mid++] == nums[mid]
则会导致结果重复,应该跳过
时间复杂度:O(n^2)
,n
为数组长度
推荐:LeetCode上的精选题解,整体思路很好,也解释了为什么不采用固定mid
的方式
(其重复情形较复杂)
3. 解
package top.actim.leetcode._15_3Sum;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
// 创建结果集
List<List<Integer>> result = new LinkedList<List<Integer>>();
// 判空
if(nums.length == 0) return result;
// 排序
Arrays.sort(nums);
// 排除均为正数或均为负数的情形
if(nums[0] > 0 || nums[nums.length - 1] < 0) return result;
// 初始化游标
int mid = 0;
int right = 0;
// 开始迭代定位
for(int left = 0; left < nums.length - 1;){
// 排除不可能情形
if(nums[left] > 0) break;
// 双游标逼近
for(mid = left + 1, right = nums.length - 1; mid < right;){
// 计算和
int sum = nums[left] + nums[mid] + nums[right];
// 符合条件
if(sum == 0){
List<Integer> item = new LinkedList<Integer>();
item.add(nums[left]);
item.add(nums[mid]);
item.add(nums[right]);
result.add(item);
}
// 游标 去重
if(sum > 0) {
while(mid < right && nums[right--] == nums[right]){}
} else {
while(mid < right && nums[mid++] == nums[mid]){}
}
// 同号判断
if(nums[left] > 0) break;
}
// 排除重复
while(left < nums.length - 1 && nums[left++] == nums[left]){}
}
return result;
}
public static void main(String[] args) {
Solution solution = new Solution();
int[] arr = {-1,-1,0,1,2,-4};
System.out.println(solution.threeSum(arr));
}
}