leetcode | 4Sum
2015-05-26 17:33
225 查看
4Sum: https://leetcode.com/problems/4sum/
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.
多加一层循环 i, j, p, q; 固定i,j; 移动 p、q夹逼;但是对于重复的元素构成,难以解决
因此可用两种解决方法
传统方法,重复时跳过
无视重复,得到所有可能,最后用 unique 和 erase 函数 去除重复
时间复杂度 O(n3)O(n^3); 空间复杂度 O(1)O(1)
利用现有函数去除重复元素:
用一个hash-table缓存所有两个数的和,枚举两个数,在hash-table中查找target-nums[i]-nums[j],得到满足条件的另外两个数,时间复杂度为O(n2)O(n^2),空间复杂度O(n2)O(n^2)
计算时间复杂度:O(n2)O(n^2)
排序 O(n lgn)O(n\ lg n) + 建立hash-table O(n2)O(n^2) + 枚举并查找 O(n2)∗O(1)O(n^2) * O(1) + 排序 O(n lgn)O(n\ lg n)
最坏时间复杂度为O(n4)O(n^4), 因为 v.size() 可能为n2n^2,此时所有组合对的key全相等
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)
解析
(1)夹逼
根据 3Sum 的夹逼思想,容易联想到4Sum的解决办法:多加一层循环 i, j, p, q; 固定i,j; 移动 p、q夹逼;但是对于重复的元素构成,难以解决
因此可用两种解决方法
传统方法,重复时跳过
无视重复,得到所有可能,最后用 unique 和 erase 函数 去除重复
时间复杂度 O(n3)O(n^3); 空间复杂度 O(1)O(1)
class Solution { public: //时间复杂度 O(n^3); 空间复杂度 O(1) vector<vector<int>> fourSum(vector<int>& nums, int target) { vector<vector<int>> result; if (nums.size() < 4) return result; sort(nums.begin(), nums.end()); for (int i = 0; i < nums.size()-3; i++) { if (i > 0 && nums[i] == nums[i-1]) continue; int t = target-nums[i]; for (int j = i+1; j < nums.size()-2; j++) { if (j > i+1 && nums[j] == nums[j-1]) //注意此处 j > i+1;不是j > 1 continue; int p = j+1; int q = nums.size()-1; while (p < q) { int sum = nums[j]+nums[p]+nums[q]; if (sum < t) { p++; while (p < q && nums[p] == nums[p-1]) p++; } else if (sum > t) { q--; while (p < q && nums[q] == nums[q+1]) q--; } else { vector<int> temp; temp.push_back(nums[i]); temp.push_back(nums[j]); temp.push_back(nums[p]); temp.push_back(nums[q]); result.push_back(temp); p++; q--; while (p < q && nums[p] == nums[p-1] && nums[q] == nums[q+1]) p++; } } } } return result; } };
利用现有函数去除重复元素:
//时间复杂度 O(n^3); 空间复杂度 O(1) class Solution { public: vector<vector<int>> fourSum(vector<int>& nums, int target) { vector<vector<int>> result; if (nums.size() < 4) return result; sort(nums.begin(), nums.end()); for (int i = 0; i < nums.size()-3; i++) { int t = target-nums[i]; for (int j = i+1; j < nums.size()-2; j++) { int p = j+1; int q = nums.size()-1; while (p < q) { int sum = nums[j]+nums[p]+nums[q]; if (sum < t) { p++; } else if (sum > t) { q--; } else { vector<int> temp; temp.push_back(nums[i]); temp.push_back(nums[j]); temp.push_back(nums[p]); temp.push_back(nums[q]); result.push_back(temp); p++; q--; } } } } //将result排序,为unique作准备 sort(result.begin(), result.end()); //unique: 移除连续且重复的元素;返回值:最后一个未被删除元素的下一个位置 //erase: 释放一定范围内的数据(内存) result.erase(unique(result.begin(), result.end()), result.end()); return result; } };
(2)hash-table
由求和等于target两个数中,将所有元素压入hash-table,寻找target-nums[i],时间复杂度是O(n)O(n) 的方法可联想:用一个hash-table缓存所有两个数的和,枚举两个数,在hash-table中查找target-nums[i]-nums[j],得到满足条件的另外两个数,时间复杂度为O(n2)O(n^2),空间复杂度O(n2)O(n^2)
计算时间复杂度:O(n2)O(n^2)
排序 O(n lgn)O(n\ lg n) + 建立hash-table O(n2)O(n^2) + 枚举并查找 O(n2)∗O(1)O(n^2) * O(1) + 排序 O(n lgn)O(n\ lg n)
最坏时间复杂度为O(n4)O(n^4), 因为 v.size() 可能为n2n^2,此时所有组合对的key全相等
// LeetCode, 4Sum // 先排序,用hash-table缓存2个数的和,枚举2个数,在hash-table查找另外2个数 // 时间复杂度O(n^2),空间复杂度O(n^2) class Solution { public: vector<vector<int>> fourSum(vector<int>& num, int target) { vector<vector<int>> result; if (num.size() < 4) return result; sort(num.begin(), num.end()); unordered_map<int, vector<pair<int, int>> > cache; //无序 hash-table for (int i = 0; i < num.size()-1; i++) { for (int j = i+1; j < num.size(); j++) cache[num[i]+num[j]].push_back(make_pair(i, j)); } for (int p = 0; p < num.size()-1; p++) { for (int q = p+1; q < num.size(); q++) { const int key = target-num[p]-num[q]; if (cache.find(key) == cache.end()) //没有找到 continue; auto v = cache[key]; //对应key值,所有的组合对, v.size()常数大小 for (int k = 0; k < v.size(); k++) { //if (num[v[k].second] > num[p]) if (v[k].second >= p) //存在重复,注:应比较脚标,而不是值 continue; vector<int> temp; temp.push_back(num[v[k].first]); temp.push_back(num[v[k].second]); temp.push_back(num[p]); temp.push_back(num[q]); result.push_back(temp); } } } sort(result.begin(), result.end()); result.erase(unique(result.begin(), result.end()), result.end()); return result; } };
测试代码
#include <vector> #include <iostream> #include <stdlib.h> #include <algorithm> #include <unordered_map> using namespace std; void PrintVector2D(vector<vector<int>>& v) { for (int i = 0; i < v.size(); i++) { for (int j = 0; j < v[i].size(); j++) cout << v[i][j] << " "; cout << endl; } } // LeetCode, 4Sum // hash-table class Solution2 { public: vector<vector<int>> fourSum(vector<int>& num, int target) { vector<vector<int>> result; if (num.size() < 4) return result; sort(num.begin(), num.end()); unordered_map<int, vector<pair<int, int>> > cache; for (int i = 0; i < num.size()-1; i++) { for (int j = i+1; j < num.size(); j++) cache[num[i]+num[j]].push_back(make_pair(i, j)); } for (int p = 0; p < num.size()-1; p++) { for (int q = p+1; q < num.size(); q++) { const int key = target-num[p]-num[q]; if (cache.find(key) == cache.end()) //没有找到 continue; auto v = cache[key]; for (int k = 0; k < v.size(); k++) { //if (num[v[k].second] > num[p]) if (v[k].second >= p) //重复,注:应比较脚标,而不是值 continue; vector<int> temp; temp.push_back(num[v[k].first]); temp.push_back(num[v[k].second]); temp.push_back(num[p]); temp.push_back(num[q]); result.push_back(temp); } } } sort(result.begin(), result.end()); result.erase(unique(result.begin(), result.end()), result.end()); return result; } }; // 夹逼 class Solution { public: vector<vector<int>> fourSum(vector<int>& nums, int target) { vector<vector<int>> result; if (nums.size() < 4) return result; sort(nums.begin(), nums.end()); for (int i = 0; i < nums.size()-3; i++) { if (i > 0 && nums[i] == nums[i-1]) continue; int t = target-nums[i]; for (int j = i+1; j < nums.size()-2; j++) { if (j > i+1 && nums[j] == nums[j-1]) continue; int p = j+1; int q = nums.size()-1; while (p < q) { int sum = nums[j]+nums[p]+nums[q]; if (sum < t) { p++; while (p < q && nums[p] == nums[p-1]) p++; } else if (sum > t) { q--; while (p < q && nums[q] == nums[q+1]) q--; } else { vector<int> temp; temp.push_back(nums[i]); temp.push_back(nums[j]); temp.push_back(nums[p]); temp.push_back(nums[q]); result.push_back(temp); p++; q--; while (p < q && nums[p] == nums[p-1] && nums[q] == nums[q+1]) p++; } } } } return result; } }; int main() { int num[] = {-3,-2,-1,0,0,1,2,3}; vector<int> nums(num, num+sizeof(num)/sizeof(num[0])); Solution sol; Solution2 sol2; vector<vector<int>>res = sol.fourSum(nums, 0); vector<vector<int>>res2 = sol2.fourSum(nums, 0); PrintVector2D(res); cout << endl << endl; PrintVector2D(res2); getchar(); }
相关文章推荐
- LeetCode 4Sum
- LeetCode 4Sum
- [LeetCode]4Sum
- [LeetCode] 4Sum
- LeetCode18:4Sum
- LeetCode 2Sum, 3Sum, 4Sum
- LeetCode 18 4Sum
- LeetCode - 18. 4Sum
- LeetCode -- 4Sum
- 4Sum——LeetCode
- 【Leetcode】之4Sum
- [LeetCode18]4Sum
- C实现 LeetCode->4Sum
- [leetcode]4Sum
- Leetcode 18 : 4sum
- 4Sum_leetCode
- 第五周:[leetcode] Two Sum、3Sum、3Sum Closest、4Sum
- 【Leetcode】4Sum (Sum)
- LeetCode 18 4Sum
- leetcode-18. 4Sum