classSolution{publicList<List<Integer>>threeSum(int[] nums){Arrays.sort(nums);//先排序,为了双指针枚举提供方便List<List<Integer>> ans =newArrayList<>();//答案需要的链表int n = nums.length;//n代表数组长度for(int i =0; i < n -2;++i){//因为需要3个数,所以第一个数最多到---倒数第3个int x = nums[i];//x保存当前遍历的第一个数if(i >0&& x == nums[i -1])continue;// 跳过重复数字,枚举过的,就不重复枚举了// 优化一:因为数组排序后是从小到大,如果当前第一个数+它后面两个数,就已经>0了,那当前枚举,包括后面的,都不会符合条件if(x + nums[i +1]+ nums[i +2]>0)break;// 优化二:如果当前数+倒数那两个数(从小到大排序,也就是末尾的都是最大的)都小于0的话,那也就不用在考虑这个枚举了。肯定枚举不出来if(x + nums[n -2]+ nums[n -1]<0)continue;//左右指针int left = i +1, right = n -1;while(left < right){//只要还有元素可以枚举就继续int s = x + nums[left]+ nums[right];//3个数的和if(s >0)--right;//如果s比0大,说明right指向的太大的,right--elseif(s <0)++left;//如果s比0小,说明left指向太小,left++else{//如果s = 0,说明找到了,添加到链表,然后将继续进行下次枚举
ans.add(List.of(x, nums[left], nums[right]));//添加到链表//进行下次枚举之前,我们可以跳过已经枚举过的,也就是和当前left和right数字重复的//因为答案中不要重复的元素for(++left; left < right && nums[left]== nums[left -1];++left);// 跳过重复数字for(--right; right > left && nums[right]== nums[right +1];--right);// 跳过重复数字}}}return ans;//返回答案}}