原题点这里
取三个数,使和为0,输出所有的组合。各个组合之间不能重复。
这是个稍微复杂一点的逻辑题。它要求所有的组合不能重复。我们很容易想到三个循环嵌套,分别取三个数,判断加和是否为0,如果为0,判断是否重复。其复杂度为n^3.
public static List<List<Integer>> threeSum(int[] nums) { HashSet<Node15> all = new HashSet<>(); int n = nums.length; List<List<Integer>> ansList=new ArrayList<>(); int ans = 0; for(int i=0;i<n;i++){ for(int j=i+1;j<n;j++){ //if(i==j) continue; for(int k=j+1;k<n;k++){ //if(j==k||i==k) continue; if(nums[i]+nums[j]+nums[k]==0){ Node15 t = new Node15(nums[i],nums[j],nums[k]); if(all.contains(t)) continue; else all.add(t); System.out.println("================================="); System.out.println(i+":"+nums[i]+" "+j+":"+nums[j]+" "+k+":"+nums[k]); List<Integer> tmp= new ArrayList<>(); tmp.add(i); tmp.add(j); tmp.add(k); ansList.add(tmp); ans++; } } } } //System.out.println(ans); return ansList; }
这样的话超时了。我们想办法优化一下。
1 重复组合的去除。我们可以不用set来去除重复项。我们对数据进行排序。然后选择一个开始遍历。选择一个数nums[i],如果nums[i]==nums[i-1],因为我们数组进行过排序,所以这个数字一定是最小值。那么同一个最小值,不重复的组合必须是剩余的两个数不同。所以我们只取一次即可。我们只要保证剩余的两个数,我们只取不同组合即可。我们使用两个指针,l=i+1,r=len-1.分别指向较小的数,和最大值。
如果 nums[i]+nums[l]+mums[r]=0,这就是一个可选的组合。然后判断,如果nums[l+1]==nums[l],我们跳过nums[l+1],以此类推。对nusm[r]和nums[r-1]也做同样的处理。
public static List<List<Integer>> threeSum2(int[] nums) { List<List<Integer>> ansList = new ArrayList<>(); Arrays.sort(nums); int len = nums.length; for(int i=0;i<len;i++){ if(nums[i]>0) break; if(i>0&&nums[i]==nums[i-1]) continue; int l = i+1; int r = len-1; while(l<r){ int ans = nums[i]+nums[l]+nums[r]; if(ans==0){ ansList.add(Arrays.asList(nums[i],nums[l],nums[r])); while(l<r&&nums[l+1]==nums[l])l++; while(l<r&&nums[r-1]==nums[r])r--; l++; r--; } else if(ans>0) r--; else if(ans<0) l++; } } //System.out.println(ans); return ansList; }