题目描述
给定一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?找出所有满足条件且不重复的三元组。
注意:答案中不可以包含重复的三元组。
例如, 给定数组 nums = [-1, 0, 1, 2, -1, -4],
满足要求的三元组集合为:
[
[-1, 0, 1],
[-1, -1, 2]
]
对时间要求特别严格,因此时刻要注意着节约,因此使用set集合来区别是否有重复的,先进行排序这样一来可以使用双指针,并且使用一个判断来避免重复的元素,这样能提高一点性能
代码(无数次的超时才在提示下撸出来效率不高的代码)
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Set<List<Integer>> tem1 = new HashSet<>();
List<List<Integer>> result = new ArrayList<List<Integer>>();
//换一个思路,遍历数组并且设置前后指针
//先进行排序一下
Arrays.sort(nums);
for (int i = 0; i < nums.length; i++) {
int j = nums[i];
int goal = -j;
int start = i+1;
int end = nums.length -1;
while (start < end) {
if(nums[start] + nums[end] > goal){
end --;
}else if (nums[start] + nums[end] < goal) {
start ++;
}else {
List<Integer> tem = new ArrayList<>();
tem.add(j);
tem.add(nums[start]);
tem.add(nums[end]);
tem1.add(tem);
int t = nums[start];
while(nums[start] == t){
start ++;
if(start >= end){
break;
}
}
t = nums[end];
while(nums[end] == t){
end --;
if(start >= end){
break;
}
}
}
}
}
for (List<Integer> list : tem1) {
result.add(list);
}
return result;
}
}
排名靠前的代码
有点复杂
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
if (nums.length < 3)
return Collections.emptyList();
List<List<Integer>> res = new ArrayList<>();
int minValue = Integer.MAX_VALUE;
int maxValue = Integer.MIN_VALUE;
int negSize = 0;
int posSize = 0;
int zeroSize = 0;
for (int v : nums) {
if (v < minValue)
minValue = v;
if (v > maxValue)
maxValue = v;
if (v > 0)
posSize++;
else if (v < 0)
negSize++;
else
zeroSize++;
}
if (zeroSize >= 3)
res.add(Arrays.asList(0, 0, 0));
if (negSize == 0 || posSize == 0)
return res;
if (minValue * 2 + maxValue > 0)
maxValue = -minValue * 2;
else if (maxValue * 2 + minValue < 0)
minValue = -maxValue * 2;
int[] map = new int[maxValue - minValue + 1];
int[] negs = new int[negSize];
int[] poses = new int[posSize];
negSize = 0;
posSize = 0;
for (int v : nums) {
if (v >= minValue && v <= maxValue) {
if (map[v - minValue]++ == 0) {
if (v > 0)
poses[posSize++] = v;
else if (v < 0)
negs[negSize++] = v;
}
}
}
Arrays.sort(poses, 0, posSize);
Arrays.sort(negs, 0, negSize);
int basej = 0;
for (int i = negSize - 1; i >= 0; i--) {
int nv = negs[i];
int minp = (-nv) >>> 1;
while (basej < posSize && poses[basej] < minp)
basej++;
for (int j = basej; j < posSize; j++) {
int pv = poses[j];
int cv = 0 - nv - pv;
if (cv >= nv && cv <= pv) {
if (cv == nv) {
if (map[nv - minValue] > 1)
res.add(Arrays.asList(nv, nv, pv));
} else if (cv == pv) {
if (map[pv - minValue] > 1)
res.add(Arrays.asList(nv, pv, pv));
} else {
if (map[cv - minValue] > 0)
res.add(Arrays.asList(nv, cv, pv));
}
} else if (cv < nv)
break;
}
}
return res;
}
}
相对靠前的代码
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> list=new ArrayList<List<Integer>>();
Arrays.sort(nums);
for (int i = 0; i <nums.length-1 ; i++) {
if (i>0&&nums[i]==nums[i-1]){
continue;//第一层遍历看是否和下一个值相等,相等就跳出这层循环,因为相等就会算重复,
// 例如-1,-1,2不判断-1和-1是否相等就会第二个-1有算出一个重的
}
int left=i+1;//两数相加的和从i+1开始。
int right=nums.length-1;
while (left<right){
if (nums[left]+nums[right]+nums[i]>0){
right--;
} else if (nums[left] + nums[right] + nums[i] < 0) {
left++;
}else {
list.add(Arrays.asList(nums[left],nums[right],nums[i]));
left++;right--;//就是不大于不小于0(等于0)的时候,做指针向右,右指针向左一动。
//这两层while就是判断如果求两数相和的时候如果左右相等就指针移动,因为走到这的时候肯定是新的
//left和right,所以就要左右指针一起判断和挨着的(下一个值)是不是相等,相等就用下一个值判断。
while (left<right&&nums[left]==nums[left-1]){
left++;
}
while (left<right&&nums[right]==nums[right+1]){
right--;
}
}
}
}
return list;
}
}