【LeetCode】18. 4Sum (2 solutions)
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)
先确定前两个数num[i],num[j],
然后设置双指针k,l分别指向两端,往中间扫。
(1)(sum = num[i]+num[j]+num[k]+num[l]) == taget,则找到其中一个解。k++,l--.
(2)sum > target, l--
(3)sum < target, k++
解法一:
用map去重
注:不可以使用unordered_map,不然会报错:
error C2440: “类型转换”: 无法从“const std::vector<_Ty>”转换为“size_t”
根据unordered_map的源码来看:
// TEMPLATE CLASS hash template<class _Kty> class hash : public unary_function<_Kty, size_t> { // hash functor public: size_t operator()(const _Kty& _Keyval) const { // hash _Keyval to size_t value by pseudorandomizing transform ldiv_t _Qrem = _CSTD ldiv((long)(size_t)_Keyval, 127773); _Qrem.rem = 16807 * _Qrem.rem - 2836 * _Qrem.quot; if (_Qrem.rem < 0) _Qrem.rem += 2147483647; return ((size_t)_Qrem.rem); } };
key必须转换为size_t类型,对应于hash表下标。
保险起见,非内置类型就不要作为unordered_map的key了。
class Solution { public: vector<vector<int> > fourSum(vector<int> &num, int target) { vector<vector<int> > result; if(num.empty() || num.size() < 4) return result; int size = num.size(); sort(num.begin(), num.end()); map<vector<int>, bool> m; for(int i = 0; i < size-3; i ++) { for(int j = i+1; j < size-2; j ++) { int k = j+1; //k < size-1 int l = size-1; while(k < l) { int sum = num[i]+num[j]+num[k]+num[l]; if(sum == target) { vector<int> cur(4,0); cur[0] = num[i]; cur[1] = num[j]; cur[2] = num[k]; cur[3] = num[l]; if(m.find(cur) == m.end()) { result.push_back(cur); m[cur] = true; } k ++; l --; } else if(sum > target) l --; else k ++; } } } return result; } };
解法二:
不用开辟新的空间,通过跳过已访问过的元素来去重。
class Solution { public: vector<vector<int> > fourSum(vector<int> &num, int target) { vector<vector<int> > ret; int size = num.size(); sort(num.begin(), num.end()); for(int i = 0; i < size; i ++) { //skip same i while(i > 0 && i < size && num[i] == num[i-1]) i ++; for(int j = i+1; j < size; j ++) { //skip same j //attention: the first element (num[i+1]) should not be skipped while(j > i+1 && j < size && num[j] == num[j-1]) j ++; int k = j + 1; int l = size - 1; while(k < l) { int sum = num[i] + num[j] + num[k] + num[l]; if(sum == target) { vector<int> cur(4); cur[0] = num[i]; cur[1] = num[j]; cur[2] = num[k]; cur[3] = num[l]; ret.push_back(cur); k ++; l --; //skip same k while(k < l && num[k] == num[k-1]) k ++; //skip same l while(l > k && num[l] == num[l+1]) l --; } else if(sum < target) { k ++; //skip same k while(k < l && num[k] == num[k-1]) k ++; } else { l --; //skip same l while(l > k && num[l] == num[l+1]) l --; } } } } return ret; } };