三数之和-力扣
方法
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
int n=nums.length;
int target;
int third;
List<List<Integer>> l=new ArrayList<List<Integer>>();
for(int fisrt=0;fisrt<n;fisrt++){
if(fisrt>0 && nums[fisrt]==nums[fisrt-1]){ //不能重复
continue;
}
target=-nums[fisrt];
third=n-1;
for(int second=fisrt+1;second<n;second++){
if(second>fisrt+1 && nums[second]==nums[second-1]){ //不能重复
continue;
}
while(second<third && nums[second]+nums[third]>target){
third--;
}
if(second==third){ //此次循环找不到target
break;
}
if(nums[second]+nums[third]==target){ //因为有可能nums[second]+nums[third]小于//target的情况
List list=new ArrayList();
list.add(nums[fisrt]);
list.add(nums[second]);
list.add(nums[third]);
l.add(list);
}
}
}
return l;
}
}
分析(截取官方核心解析)
「不重复」的本质是什么?我们保持三重循环的大框架不变,只需要保证:
第二重循环枚举到的元素不小于当前第一重循环枚举到的元素;
第三重循环枚举到的元素不小于当前第二重循环枚举到的元素。
也就是说,我们枚举的三元组 (a, b, c)(a,b,c) 满足 a \leq b \leq ca≤b≤c,保证了只有 (a, b, c)(a,b,c) 这个顺序会被枚举到,而 (b, a, c)(b,a,c)、(c, b, a)(c,b,a) 等等这些不会,这样就减少了重复。要实现这一点,我们可以将数组中的元素从小到大进行排序,随后使用普通的三重循环就可以满足上面的要求。
同时,对于每一重循环而言,相邻两次枚举的元素不能相同,否则也会造成重复。举个例子,如果排完序的数组为
[0, 1, 2, 2, 2, 3]
^ ^ ^
我们使用三重循环枚举到的第一个三元组为 (0, 1, 2)(0,1,2),如果第三重循环继续枚举下一个元素,那么仍然是三元组 (0, 1, 2)(0,1,2),产生了重复。因此我们需要将第三重循环「跳到」下一个不相同的元素,即数组中的最后一个元素 33,枚举三元组 (0, 1, 3)(0,1,3)。