這三道題目都是一個類型,主要就是利用有序數組與雙指針的一些技巧;
首先給出一個基本模板,如何在一個有序數組中找到兩數之和爲一目標值target;
int l=0,r=nums.size()-1;
while(l<r)
{
if(nums[l]+nums[r]==target)
{
//根據不同的要求,進行一些必要的操作
//考慮是否去重
}
else if(nums[l]+nums[r]<target)
++l;
else
--r;
}
1.首先看leetcode 15 三數之和
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>>res;
if(nums.size()<3)return{};
sort(nums.begin(),nums.end());
for(int i=0;i<nums.size()-2;++i)
{
int l=i+1,r=nums.size()-1;
if(i>0&&nums[i]==nums[i-1])continue;//去重複
while(l<r)
{
auto sum=nums[l]+nums[r]+nums[i];
if(0==sum)
{
res.push_back({nums[i],nums[l],nums[r]});
while(l+1<r&&nums[l]==nums[l+1])//去重複
++l;
while(r-1>l&&nums[r]==nums[r-1])//去重複
--r;
++l;
--r;
}
else if(sum<0)
++l;
else
--r;
}
}
return res;
}
};
核心部分就是while(l<r)
那個循環,也就是上述的模板,主要有兩個關鍵點;
1.當我們找到和一個目標值的子數組時,需要去重複,也就是將l
不斷的右移動,r
不斷向左移動;
2.外層循環對nums[i]
,也有同樣的去重複操作;
2.leetcode16 最接近的三數之和
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
sort(nums.begin(),nums.end());
int mind=nums[0]+nums[1]+nums[2];
for(int i=0;i<=nums.size()-3;++i)
{
int l=i+1,r=nums.size()-1;
while(l<r)
{
int sum=nums[i]+nums[l]+nums[r];
if(abs(sum-target)<abs(mind-target))
mind=sum;
if(sum<target)
++l;
else if(sum>target)
--r;
else return sum;
}
}
return mind;
}
};
和上一題相比,更加簡單,沒有了去重複操作,在while()
循環裏只需要不斷的更新最小的距離即可;
3.leetcode 18 四數之和
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
if(nums.size()<4)return {};
vector<vector<int>>res;
sort(nums.begin(),nums.end());
for(int i=0;i<nums.size()-3;++i)
{
if(i>0&&nums[i-1]==nums[i])continue;
for(int j=i+1;j<nums.size()-1;++j)
{
if(j>i+1&&nums[j-1]==nums[j])continue;
int l=j+1,r=nums.size()-1;
while(l<r)
{
auto sum=nums[i]+nums[j]+nums[l]+nums[r];
if(sum==target)
{
res.push_back({nums[i],nums[j],nums[l],nums[r]});
while(l<r&&nums[l]==nums[l+1])
++l;
while(l<r&&nums[r]==nums[r-1])
--r;
++l;
--r;
}
else if(sum>target)
--r;
else
++l;
}
}
}
return res;
}
};
與三數之和最大的區別是它增加了一層循環,此外沒有任何變化,尤其是while()
循環裏核心代碼一模一樣;
總結:對於有序數組相關的問題,雙指針是一個比較重要的技巧;當然上面的題目也可以用哈希表或者紅黑樹來做,但是時間複雜度方面沒有提升,還增加了空間複雜度,所以不算是最優的解法。