Leetcode | 3Sum
Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note:
Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)
The solution set must not contain duplicate triplets.
For example, given array S = {-1 0 1 2 -1 -4},
A solution set is:
(-1, 0, 1)
(-1, -1, 2)
主要在去重方面走了弯路。思路同Two sum.
从num中取出一个数,就要把它的所有和为0的组合找出来。
找到一组之后,找下一组,i++,j--,但是要注意去重。
取出一个数的时候,就从它后面开始找其他两个数,因为在他之间的数已经找过了。 i = k + 1;
确定范围之后,下一个k必须要忽略相同的数(Line 12) num[k] != num[k+1],k++。
1 vector<vector<int> > threeSum(vector<int> &num) { 2 vector<vector<int> > ret; 3 if (num.size() < 3) return ret; 4 5 vector<int> v; 6 sort(num.begin(), num.end()); 7 8 for (int k = 0; k < num.size(); ++k) { 9 // get num[k], search in [k + 1, n - 1] 10 int i = k + 1, j = num.size() - 1; 11 12 // ignore duplicate num[k] 13 while (k < num.size() - 1 && num[k] == num[k + 1]) k++; 14 15 while (j > i) { 16 int s = num[i] + num[j]; 17 18 if (s == -num[k]) { 19 v.push_back(num[i]); 20 v.push_back(num[k]); 21 v.push_back(num[j]); 22 sort(v.begin(), v.end()); 23 ret.push_back(v); 24 v.clear(); 25 26 // continue to find another match 27 i++; 28 while (i <= j && num[i] == num[i - 1]) i++; 29 j--; 30 while (j >= i && num[j] == num[j + 1]) j--; 31 } else if (s > -num[k]) { 32 j--; 33 } else { 34 i++; 35 } 36 } 37 } 38 39 return ret; 40 }
写得简洁一点。
1 class Solution { 2 public: 3 vector<vector<int> > threeSum(vector<int> &num) { 4 vector<vector<int> > ans; 5 if (num.empty()) return ans; 6 sort(num.begin(), num.end()); 7 int n = num.size(); 8 for (int i = 0; i + 2 < n; ) { 9 int target = -num[i]; 10 for (int j = i + 1, k = n - 1; j < k; ) { 11 int sum = num[j] + num[k]; 12 if (sum == target) { // sum + num[i] == 0 13 vector<int> tmp = {num[i], num[j], num[k]}; 14 sort(tmp.begin(), tmp.end()); 15 ans.push_back(tmp); 16 for (++j; j < k && num[j] == num[j - 1]; ++j); // ignore dups 17 for (--k; k > j && num[k] == num[k + 1]; --k); 18 } else if (sum < target) { 19 j++; 20 } else { 21 k--; 22 } 23 } 24 for (++i; i + 2 < n && num[i] == num[i - 1]; ++i); 25 } 26 27 return ans; 28 } 29 };
3Sum Closest
Given an array S of n integers, find three integers in S such that the sum is closest to a given number, target. Return the sum of the three integers. You may assume that each input would have exactly one solution.
For example, given array S = {-1 2 1 -4}, and target = 1.
The sum that is closest to the target is 2. (-1 + 2 + 1 = 2).
和3 sum类似,就是在查找的时候,必须跟踪最小的差值。
1 class Solution { 2 public: 3 int threeSumClosest(vector<int> &num, int target) { 4 if (num.size() < 3) return INT_MAX; 5 6 sort(num.begin(), num.end()); 7 int minDiff = INT_MAX, minSum = target; 8 for (int k = 0; k < num.size(); ++k) { 9 // get num[k], search in [k + 1, n - 1] 10 int i = k + 1, j = num.size() - 1; 11 12 int t = target - num[k]; 13 14 while (j > i) { 15 int s = num[i] + num[j]; 16 if (abs(s - t) < minDiff) { 17 minDiff = abs(s - t); 18 minSum = s + num[k]; 19 } 20 if (s == t) { 21 return target; 22 } else if (s > t) { 23 j--; 24 } else { 25 i++; 26 } 27 } 28 29 // ignore duplicate num[k] 30 while (k < num.size() - 1 && num[k] == num[k + 1]) k++; 31 } 32 33 return minSum; 34 } 35 };
4Sum
Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.
Note:
Elements in a quadruplet (a,b,c,d) must be in non-descending order. (ie, a ≤ b ≤ c ≤ d)
The solution set must not contain duplicate quadruplets.
For example, given array S = {1 0 -1 0 -2 2}, and target = 0.
A solution set is:
(-1, 0, 0, 1)
(-2, -1, 1, 2)
(-2, 0, 0, 2)
3 sum类似,加了一层。244ms.
1 class Solution { 2 public: 3 vector<vector<int> > fourSum(vector<int> &num, int target) { 4 vector<vector<int> > ret; 5 if (num.size() < 4) return ret; 6 7 vector<int> v; 8 sort(num.begin(), num.end()); 9 10 for (int m = 0; m < num.size(); ++m) { 11 for (int k = m + 1; k < num.size(); ++k) { 12 // get num[k], search in [k + 1, n - 1] 13 int i = k + 1, j = num.size() - 1; 14 int t = target - num[m] - num[k]; 15 // ignore duplicate num[k] 16 while (k < num.size() - 1 && num[k] == num[k + 1]) k++; 17 18 while (j > i) { 19 int s = num[i] + num[j]; 20 21 if (s == t) { 22 v.push_back(num[m]); 23 v.push_back(num[k]); 24 v.push_back(num[i]); 25 v.push_back(num[j]); 26 sort(v.begin(), v.end()); 27 ret.push_back(v); 28 v.clear(); 29 30 // continue to find another match 31 i++; 32 while (i <= j && num[i] == num[i - 1]) i++; 33 j--; 34 while (j >= i && num[j] == num[j + 1]) j--; 35 } else if (s > t) { 36 j--; 37 } else { 38 i++; 39 } 40 } 41 } 42 while (m < num.size() - 1 && num[m] == num[m + 1]) m++; 43 } 44 return ret; 45 } 46 };
4 sum有O(n^2)的解法,leetcode的discuss后面有。但是那个代码760ms。按照同样的思路,用set来去重,也是760ms。
1 class Solution { 2 public: 3 vector<vector<int> > fourSum(vector<int> &num, int target) { 4 vector<vector<int> > ret; 5 if (num.size() < 4) return ret; 6 7 sort(num.begin(), num.end()); 8 9 map<int, vector<pair<int, int> > > sums; 10 11 for (int i = 0; i < num.size(); ++i) { 12 for (int j = i + 1; j < num.size(); ++j) { 13 sums[num[i] + num[j]].push_back(pair<int, int>(i, j)); 14 } 15 } 16 17 map<int, vector<pair<int, int> > >::iterator it; 18 vector<int> v; 19 set<vector<int> > r; 20 for (int i = 0; i < num.size(); ++i) { 21 for (int j = i + 1; j < num.size(); ++j) { 22 int s = target - num[i] - num[j]; 23 if ((it = sums.find(s)) != sums.end()) { 24 for (vector<pair<int, int>>::iterator it2 = it->second.begin(); 25 it2 != it->second.end(); ++it2) { 26 if (it2->first <= j) continue; 27 v.push_back(num[i]); 28 v.push_back(num[j]); 29 v.push_back(num[it2->first]); 30 v.push_back(num[it2->second]); 31 r.insert(v); 32 v.clear(); 33 } 34 } 35 } 36 } 37 38 for (set<vector<int> >::iterator it = r.begin(); it != r.end(); it++) { 39 ret.push_back(*it); 40 } 41 return ret; 42 } 43 };