3Sum algorithm, 3 sumalgorithm
Repeat the original question: (click an image to go to the source link)
The Chinese explanation for this question is,
Enter an array, for example, {-1 0 1 2-1-4}, and find three numbers (a, B, c) from the array to make it and 0, output all (a, B, c) combinations.
Abc must not be repeated, and a <= B <= c.
When getting this question, Every programmer can think of the following algorithm, namely brute-force cracking. the time complexity is o (n ^ 3 ):
1 for(int i=0;i<nums.length;i++){2 for(int j=i+1;j<nums.length;j++){3 for(int k=j+1;k<nums.length;j++){4 if(nums[i]+nums[j]+nums[k]==0){5 addResult(nums[i], nums[j], nums[k]); 6 }7 }8 }9 }
First, sort the input array. In this way, nums [I] <nums [j] <nums [k] can be guaranteed because of the I <j <k] above.
In fact, my algorithm is optimized based on brute-force cracking to minimize time complexity.
The method for sorting Arrays in java is: Arrays. sort (nums );
The third loop is actually unnecessary, because after the I and j values are determined, the nums [k] value to be searched has been determined, -(nums [I] + nums [j]).
Therefore, you only need to judge whether this value exists in the remaining elements of the array.
Based on this idea, I constructed a hashmap as a hash index table to find the location where each value appears: (considering that a value may appear in multiple locations, use arraylist)
Because nums has been sorted, The arraylist in the index table is also sorted.
HashMap<Integer, ArrayList<Integer>> index = new HashMap<>();
The code for constructing the index table is as follows:
1 for(int i=0;i<nums.length;i++){ 2 int num = nums[i]; 3 if(num==0){ 4 n++; 5 } 6 if(index.get(num)==null){ 7 8 9 index.put(num, new ArrayList<Integer>());10 }11 12 index.get(num).add(i);13 14 15 }
N indicates the number of zeros. If n> = 3, a [0 0 0] is output directly.
I have been thinking about the number method required to query the index table for a long time. Finally, I came up with a very good method:
1 int p = -(nums[i]+nums[j]); 2 if(p<0) continue; 3 ArrayList<Integer> in = index.get(p); 4 if(in==null) continue; 5 if(in.get(in.size()-1)>j){ 6 if(p>nums[j]){ 7 addResult(nums[i], nums[j],p); 8 }else if(p>nums[i]){ 9 addResult(nums[i], p,nums[j]);10 }else{11 addResult(p,nums[i], nums[j]);12 }13 14 }
Why should p <0 be discarded in Row 3? Because we need to avoid repetition. If p is also a negative number, nums [I] <nums [j] may cause two problems:
① Nums [I] And nums [j] are both positive numbers;
② Nums [I] is a negative number, and nums [j] is a positive number.
In other scanning processes, the following will occur:
① Nums [I] '= p, p' = nums [I], nums [j]' = nums [j] at that time;
② P '= nums [j], nums [I]' = min (nums [I], p), nums [j] '= max (nums [I], p ).
5th rows in. get (in. size ()-1)> what does j mean?
At this time, we need to find a k (k> j) so that nums [k] = p. If yes, nums [k] is output.
ArrayList in indicates that all k values of nums [k] = p are obtained. If the maximum k value is greater than j, then k> j exists, so does nums [k] = p?
K> j is required, because the following situations do not meet the requirements:
Input [-1 0 1 2] cannot output [-1-1 2] Because the index of-1 is [0], it does not meet k> j
To avoid duplication,
I use the addResult function to avoid repetition. you should understand it at first glance.
1 HashSet <String> repeat = new HashSet <String> (); // re-query 2 List <Integer> result = new distinct List <Integer> (); 3 4 5 public void addResult (int n1, int n2, int n3) {6 String s = n1 + "&" + n2; 7 8 if (! Repeat. contains (s) {9 List <Integer> p = new ArrayList <> (); 10 p. add (n1); 11 p. add (n2); 12 p. add (n3); 13 result. add (p); 14 repeat. add (s); 15} 16}
The detailed code is as follows:
1 import java. util. arrayList; 2 import java. util. arrays; 3 import java. util. hashMap; 4 import java. util. hashSet; 5 import java. util. using list; 6 import java. util. list; 7 8/** 9 * optimized o (n ^ 2) 3sum algorithm 10 * @ author user 11*12 */13 public class Solution {14 HashSet <String> repeat = new HashSet <String> (); // check the 15th List <Integer> result = new upload List <Integer> (); 16 17 18 public void add Result (int n1, int n2, int n3) {19 String s = n1 + "&" + n2; 20 21 if (! Repeat. contains (s) {22 List <Integer> p = new ArrayList <> (); 23 p. add (n1); 24 p. add (n2); 25 p. add (n3); 26 result. add (p); 27 repeat. add (s); 28} 29} 30 31 32 33 34 public List <Integer> threeSum (int [] nums) {35 if (nums. length <3) {36 return result; 37} 38 Arrays. sort (nums); 39 if (nums. length = 3) {40 if (nums [0] + nums [1] + nums [2] = 0) {41 42 addResult (nums [0], nums [1], nums [2]); 43 return result; 44} else {45 return result; 46} 47} 48 HashMap <Integer, arrayList <Integer> index = new HashMap <> (); 49 int n = 0; 50 51 for (int I = 0; I <nums. length; I ++) {52 int num = nums [I]; 53 if (num = 0) {54 n ++; 55} 56 if (index. get (num) = null) {57 58 59 index. put (num, new ArrayList <Integer> (); 60} 61 62 index. get (num ). add (I); 63 64 65} 66 if (n> = 3) addResult (0, 0, 0); 67 68 69 70 71 for (int I = 0; I <nums. length; I ++) {72 if (nums [I] <0 & nums [nums. length-1] <-I) | (nums [I]> 0 & nums [0]>-nums [I]) continue; 73 74 for (int j = I + 1; j <nums. length; j ++) {75 76 77 78 int p =-(nums [I] + nums [j]); 79 80 if (p <0) continue; 81 ArrayList <Integer> in = index. get (p); 82 if (in = null) continue; 83 if (in. get (in. size ()-1)> j) {84 if (p> nums [j]) {85 addResult (nums [I], nums [j], p ); 86} else if (p> nums [I]) {87 addResult (nums [I], p, nums [j]); 88} else {89 addResult (p, nums [I], nums [j]); 90} 91 92} 93 94 95 96} 97 99 100 101} 102 103 return result; 104} 105 106 107 108 109 110 public static void main (String [] args) {111 long m = System. currentTimeMillis (); 112 int a [] = {-1,-2,-3 }; 113 114 Solution solution = new Solution (); 115 System. out. println (solution. threeSum (). size (); 116 117 long n = System. currentTimeMillis (); 118 System. out. println (n-m); 119 120} 121 122}View Code