给你一个包含 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
【解答】
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> ans = new ArrayList<>();
int len = nums.length;
if (len < 3) return ans;
int minValue = Integer.MAX_VALUE, maxValue = Integer.MIN_VALUE;
int minusCount = 0, zeroCount = 0, plusCount = 0;
for (int num : nums) {
minValue = Math.min(minValue, num);
maxValue = Math.max(maxValue, num);
if (num < 0) {
minusCount++;
} else if (num == 0) {
zeroCount++;
} else {
plusCount++;
}
}
if (zeroCount >= 3) {
ans.add(Arrays.asList(0, 0, 0));
}
if (minusCount == 0 || plusCount == 0) {
return ans;
}
//排除边界不可能和其他数凑成0的
if (((minValue << 1) + maxValue) < 0) {
minValue = -maxValue << 1;
} else if (((maxValue << 1) + minValue) > 0) {
maxValue = -minValue << 1;
}
//记录各个数字的出现次数、去重的负数和正数
int[] count = new int[maxValue - minValue + 1];
int[] minus = new int[minusCount];
int[] plus = new int[plusCount];
//记录去重的负数和正数的数量
minusCount = 0;
plusCount = 0;
for (int num : nums) {
if (num < minValue || num > maxValue) continue;
//去重
if (count[num - minValue]++ != 0) continue;
if (num < 0) {
minus[minusCount++] = num;
} else if (num > 0) {
plus[plusCount++] = num;
}
}
//排序
Arrays.sort(minus, 0, minusCount);
Arrays.sort(plus, 0, plusCount);
//从小开始遍历,左右收敛,结果肯定会有一个正数和一个负数
int plusBegin = 0;
int curMinus;
for (int i = minusCount - 1; i >= 0; i--) {
curMinus = minus[i];
int minPlus = curMinus << 1;
while (plusBegin < plusCount && plus[plusBegin] < minPlus) {
plusBegin++;
}
for (int j = plusBegin; j < plusCount; j++) {
int curPlus = plus[j];
int remain = -curMinus - curPlus;
if (remain < curMinus) {
break;
} else if (remain == curMinus && count[remain - minValue] > 1) {
ans.add(Arrays.asList(curMinus, remain, curPlus));
} else if (remain == curPlus && count[remain - minValue] > 1) {
ans.add(Arrays.asList(curMinus, remain, curPlus));
} else if (remain > curMinus && remain < curPlus && count[remain - minValue] > 0) {
ans.add(Arrays.asList(curMinus, remain, curPlus));
}
}
}
return ans;
}