这个可以扩展到n数之和
时间复杂度如果暴力匹配的话可以达到O(N^n)
基本上首先需要sort给的数据,这样复杂度就会变成 O(N^(n-1)) ,快速排序的复杂度 O(nlogn)在大O表示法中被省去
如果sort之后,整个数据有序了,我们就可以指定前 N-2个,然后通过左右夹逼的方式,找出剩下的2个数,如果时暴力查找的话复杂度时O(n^2),但是现在是O(n)
这个实现起来其实很简单,但是一个问题是去重,给出的N元组合可能重复。
可以建一个set来暴力去重,但是效率比较低。可以采取和前驱对比的方法。
下面上代码:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> res;
if (nums.size() < 3) return res;
sort(nums.begin(),nums.end());
for (int i = 0; i < nums.size()-2; i++)
{
int left = i + 1;
int right = nums.size() -1;
if (i > 0 && nums[i] == nums[i - 1]) continue; //去重
while (left < right)
{
if (nums[left]+nums[right] == -nums[i])
{
vector<int> tmp = {nums[i],nums[left],nums[right]};
res.push_back(tmp);
left++;
right--;
while (left < right && nums[left] == nums[left - 1]) left++; //去重
while (left < right && nums[right] == nums[right + 1]) right--; //去重
}
else if (nums[left]+nums[right] < -nums[i])
{
left++;
}
else
{
right--;
}
}
}
return res;
}
};
注意标着去重注释的那几行。
都是在和前驱做比较,如果和前驱一样,这次循环就跳过了,比如 如果三元组的第一个数字遍历到[...4,4],这里如果要避免重复三元组肯定不能选两次4。因为数据集是有序的,所以这样和前驱对比就能去重。
下面是4数之和
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
vector<vector<int>> res;
if (nums.size() < 4) return res;
for (int i = 0; i < nums.size()-3; i++)
{
if (i > 0 && nums[i] == nums[i-1]) continue; //去重
for (int j = i+1; j < nums.size()-2; j++)
{
if (j > i+1 && nums[j] == nums[j-1]) continue; //去重
int left = j+1;
int right = nums.size()-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);
left++;
right--;
while (left < right && nums[left-1] == nums[left]) left++; //去重
while (left < right && nums[right+1] == nums[right]) right--; //去重
}
else if (sum < target)
{
left++;
}
else
{
right--;
}
}
}
}
return res;
}
};
偷懒就多套了一个循环,实际上可以改成递归来支持N数之和的寻找
if (j > i+1 && nums[j] == nums[j-1]) continue;
上面这句最开始错了,写成 j > 0,抄错了,要从i + 1开始。