給定一個包含 n 個整數的數組 nums 和一個目標值 target,判斷 nums 中是否存在四個元素 a,b,c 和 d ,使得 a + b + c + d 的值與 target 相等?找出所有滿足條件且不重複的四元組。
注意:
答案中不可以包含重複的四元組。
示例:
給定數組 nums = [1, 0, -1, 0, -2, 2],和 target = 0。
滿足要求的四元組集合爲:
[
[-1, 0, 0, 1],
[-2, -1, 1, 2],
[-2, 0, 0, 2]
]
來源:力扣(LeetCode)
分析一
與TwoSum的思想相似,通過計算兩數之和並將(nums[i]+nums[j],(i,j))鍵值對記錄在map中,從生成的鍵值對中遍歷,再搜索另一個key相加等於target的鍵值對,化爲兩數之和。
兩數之和的博客:兩數之和
- tips
- 使用unordered_multimap可以存儲重複的關鍵字。
multimap可以存儲重複的key,但是不能重載operator[] ,如 multimap<int,int> mp;mp[key]=1; 這裏的mp[key]=1是不允許的。 - 由於等於key的鍵值對可能有多個是,所以用equal_range(key)來訪問查找到的鍵值對,multimap 的find() 查找到的是第一個滿足條件的鍵值對。
代碼
class Solution {
public:
//使用unordered_multimap存儲可重複的鍵值對
//multimap可以存儲重複的key,但是不能重載operator[] ,如 multimap<int,int> mp;mp[key]=1; //mp[key]=1是不允許的
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> res;
if(nums.size()<4) return res;
unordered_multimap<int,pair<int,int>> mp;
int numsSize=nums.size();
for(int i=0;i<numsSize;i++)
for(int j=i+1;j<numsSize;j++){
mp.insert(make_pair(nums[i]+nums[j],make_pair(i,j)));
}
for(auto it1=mp.begin();it1!=mp.end();it1++){
int key=target-it1->first;
auto range=mp.equal_range(key);
//由於等於key的鍵值對可能有多個是,所以用equal_range(key)來訪問查找到的鍵值對
//multimap 的find() 查找到的是第一個滿足條件的鍵值對
for(auto it2=range.first;it2!=range.second;it2++){
auto i=it1->second.first;
auto j=it1->second.second;
auto c=it2->second.first;
auto d=it2->second.second;
if(i!=c&&i!=d&&j!=c&&j!=d){
vector<int> tmp{nums[i],nums[j],nums[c],nums[d]};
sort(tmp.begin(),tmp.end());
res.push_back(tmp);
}
}
}
sort(res.begin(),res.end());
res.erase(unique(res.begin(),res.end()),res.end());
return res;
}
};
分析二
與三數之和的思想類比,先用二重循環獲得num[i]、nums[j],再通過雙指針法使用三數之和的方法查找 nums[j]+nums[left]+nums[right]==target-nums[i]。
上一篇三數之和的博客:三數之和
代碼
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> res;
if(nums.size()<4) return res;
int numsSize=nums.size();
sort(nums.begin(),nums.end());
for(int i=0;i<numsSize-3;i++){
if(i!=0&&nums[i]==nums[i-1]) continue;
int min=nums[i]+nums[i+1]+nums[i+2]+nums[i+3];
if(min>target) continue; //是continue不是break!
int max=nums[i]+nums[numsSize-1]+nums[numsSize-2]+nums[numsSize-3];
if(max<target) continue;
for(int j=i+1;j<numsSize-2;j++){
if(j>i+1&&nums[j]==nums[j-1]) continue;
int min=nums[i]+nums[j]+nums[j+1]+nums[j+2];
if(min>target) continue;
int max=nums[i]+nums[j]+nums[numsSize-1]+nums[numsSize-2];
if(max<target) continue;
int left=j+1,right=numsSize-1;
while(left<right){
int sum=nums[i]+nums[j]+nums[left]+nums[right];
if(sum==target){
vector<int> tmp{nums[i],nums[j],nums[left],nums[right]};
res.push_back(tmp);
int dup1=nums[left];
int dup2=nums[right];
while(left<right&&nums[left]==dup1) left++;
while(left<right&&nums[right]==dup2) right--;
}else if(sum<target)
left++;
else
right--;
}
}
}
return res;
}
};