最近leetcode也刷了100道了,开始二刷这100道题,并做每道做过题的相似题目;
leetcode的第一题是两数之和,还有三数之和,四数之和… 其实他们都可以用相同的方法来解决,甚至可以一直推到n数之和!
三数之和
假如求两数之和,我们可以先将数组从大到小排序,然后用双指针的方法从两头往内收缩寻找:
int i = 0;
int j = nums.size() - 1;
while(i<j)
{
if(nums[i]+nums[j] == target){
while(i<j&&nums[j-1] == nums[j])
j--;
while(i<j&&nums[i] == nums[i+1])
i++;
vector<int> tmp = {nums[i],nums[j]};
res.push_back(tmp);
i++;
j--;
}
else if(nums[i]+nums[j] > target)
{
while(i<j&&nums[j-1] == nums[j])
j--;
j--;
}
else{
while(i<j&&nums[i] == nums[i+1])
i++;
i++;
}
}
这个方法的时间复杂度近似为O(n),两数之和的复杂度可以到O(n),那么三数之和的复杂度应该可以到O(n*n),我们可以固定一个数,然后对后两个数用这个两数之和的方法,还要注意去除重复!:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
sort(nums.begin(),nums.end());
for(int m = 0;m<nums.size();m++)
{
if(nums[m] > 0)
return res;
if(m>0&&nums[m]==nums[m-1])
continue;
int i = m+1;
int j = nums.size() - 1;
int target = nums[m];
while(i<j)
{
if(target+nums[i]+nums[j] == 0){
while(i<j&&nums[j-1] == nums[j])
j--;
while(i<j&&nums[i] == nums[i+1])
i++;
vector<int> tmp = {nums[i],nums[j],target};
res.push_back(tmp);
i++;
j--;
}
else if(target+nums[i]+nums[j] > 0)
{
while(i<j&&nums[j-1] == nums[j])
j--;
j--;
}
else{
while(i<j&&nums[i] == nums[i+1])
i++;
i++;
}
}
}
return res;
}
};
四数之和
同理,我们可以先固定前两个数,然后再次使用两数之和的方法,把原本暴力法O(nnnn)降为O(nn*n)
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> res;
sort(nums.begin(),nums.end());
if(nums.size()<4)
return res;
for(int m = 0;m<nums.size()-3;m++){
// if(nums[m]>target)
// return res;
if(m>0&&nums[m] == nums[m-1])
continue;
for(int n = m+1;n<nums.size()-2;n++){
// if(nums[m]+nums[n]>target)
// break;
if(n>m+1&&nums[n] == nums[n-1])
continue;
int i = n+1;
int j = nums.size()-1;
while(i<j){
if(nums[m]+nums[n]+nums[i]+nums[j]==target){
while(i<j&&nums[i]==nums[i+1]) i++;
while(i<j&&nums[j]==nums[j-1]) j--;
vector<int> tmp = {nums[m],nums[n],nums[i],nums[j]};
res.push_back(tmp);
i++;
j--;
}
else if(nums[m]+nums[n]+nums[i]+nums[j]>target) {
while(i<j&&nums[j]==nums[j-1])
j--;
j--;
}
else {
while(i<j&&nums[i]==nums[i+1])
i++;
i++;
}
}
}
}
return res;
}
};