三数之和
什么是三数之和
三数之和,概括起来说就说从一个数组中找到三个数,使三数之和等于目标值。
思路
处理N数之和的问题时,我们首先肯定是对数组进行排序,那么这个问题就变成了从有序数组中找到三个这样的数字能够加起来成为target值。首先想到的是利用暴力解法,三层for循环简单粗暴的解决问题,但是暴力法的会超出时间限制。因此我们需要换一种思路,用双指针法,可以降低一下时间空间复杂度。
例子
这一题的话,有一个关键性的要求是答案是不重复的,因此我们需要做一个去重的操作,去重的操作也是十分的巧妙,在代码中做了注释。
class Solution {
public:
vector<vector<int>> twoSum(vector<int>&nums,int left,int right,int target,int value)
{ vector<vector<int>>answers;
while(left<right)
{
if(nums[left]+nums[right]==target)
{
vector<int>results;
results.push_back(value);
results.push_back(nums[left]);
results.push_back(nums[right]);
answers.push_back(results);
//如果left下一个元素等于当前的left值,那么跳过,去除重复寻值
while(left<right && nums[left]==nums[left+1])
left++;
//如果right上一个元素等于当前的right值,那么跳过,去除重复寻值
while(left<right && nums[right]==nums[right-1])
right--;
left++;
right--;
}
else if(nums[right]+nums[left]>target)
right--;
else
left++;
}
return answers;
}
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>>answers;
int n=nums.size();
sort(nums.begin(),nums.end());
//枚举a,枚举a的过程中要跳过重复值
for(int i=0;i<n;i++)
{
//枚举a,枚举a的过程中要跳过重复值
if(i>0 && nums[i]==nums[i-1])
continue;
auto result=twoSum(nums,i+1,n-1,-nums[i],nums[i]);
answers.insert(answers.end(),result.begin(),result.end());
}
return answers;
}
};
四数之和
思路
三数之和下面有了四数之和,方法一样,只是加了一层for循环。都是排序+双指针的思路。
代码
class Solution {
public:
vector<vector<int>>twoSum(vector<int>& nums, long target,int left,int right,int i,int j)
{
vector<vector<int>>answers;
while(left<right)
{
if((long)nums[left]+(long)nums[right]==target)
{
vector<int>result;
result.push_back(nums[i]);
result.push_back(nums[j]);
result.push_back(nums[left]);
result.push_back(nums[right]);
answers.push_back(result);
while(left<right && nums[left]==nums[left+1])
left++;
while(left<right && nums[right]==nums[right-1])
right--;
left++;
right--;
}
else if(nums[left]+nums[right]>target)
right--;
else
left++;
}
return answers;
}
vector<vector<int>> fourSum(vector<int>& nums, int target) {
//nums中的四个不同元素加在一起等于target
//是否能利用三数之和
//先用枚举法试试,枚举的过程中出现了溢出
//既然三数之和用到了二数之和,是否四数也可以
int n=nums.size();
sort(nums.begin(),nums.end());
long long target_num;
vector<vector<int>>answers;
//枚举a
for(int i=0;i<=n-4;i++)
{
//避免重复值
if(i>0&&nums[i-1]==nums[i])
{
continue;
}
//枚举b
for(int j=i+1;j<=n-3;j++)
{
if(j>i+1 && nums[j-1]==nums[j])
continue;
//cout<<"i:"<<i<<" "<<"j:"<<j<<" ";
target_num=target-(long)nums[i]-(long)nums[j];
//cout<<nums[i];
//cout<<"待寻找的值:"<<target_num<<endl;
auto result=twoSum(nums,target_num,j+1,n-1,i,j);
answers.insert(answers.end(),result.begin(),result.end());
}
}
return answers;
}
};
最接近的三数之和
思路
这题和上面都不一样,这题如果没有恰好等于target的三数之和的话,可以找一个最接近的,也是用双指针法。
代码
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
//暴力法会超时
int n=nums.size();
sort(nums.begin(),nums.end());
int best=1e7;
int res;
//双指针
for(int i=0;i<n;i++)
{
int left=i+1,right=n-1;
while(left<right)
{
int temp=nums[left]+nums[right]+nums[i];
int diff=target-temp;
if(temp==target)
return temp;
if(target>temp)
left++;
else
right--;
if(abs(diff)<best)
{
best=abs(diff);
res=temp;
}
}
}
return res;
}
};