题目地址
https://leetcode.com/problems/4sum/
题目大意
有一组数a[n]
,给定一个目标数target
,从a[n]
找出4个数,使得sum(a[i], a[j], a[p], a[q]) = target
。输出所有这样的4个数的组合。并且组合中的数要从小到大排列。
解题思路
这是一系列的题目,叫做k sum
。求解k sum
的方法,可以通过求解2sum
来推导。
2sum
求解2sum
想到的最暴力的方法是遍历所有组合,然后找出符合要求的。这时的时间复杂度为O(n^2)
。
有没有更简单的方法呢。显然是有的。我们可以先将数组排序。然后使用两个指针,分别指向数组的头和尾然后使用如下的方法来遍历这个数组。
int left = 0;
int right = n - 1;
while (left < right) {
int sum = a[left] + a[right];
if (sum == target) {
record_left_right(left, right);
} else if (sum < target) {
left++;
} else {
right--;
}
}
这样,我们的时间复杂度就为O(nlogn) + O(n) = O(nlogn)
推广到K sum
对于所有的k sum
,我们都能把它退化为 k-1 sum
。方法是,选定一个数a[i]
,然后计算new_target = target - a[i]
的k - 1 sum
问题。
这样,我们可得 k sum(k >= 3)
的时间复杂度为O(nlogn) + O(n^(k - 1)) = O(n^(k - 1))
源码
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> result;
int num_num = nums.size();
if (num_num < 4) {
return result;
}
sort(nums.begin(), nums.end());
set<vector<int>> tmpres;
for (int outer = 0; outer < num_num; ++outer) {
for (int inner = outer + 1; inner < num_num; ++inner) {
int left = inner + 1;
int right = num_num - 1;
while (right > left) {
int tmp_result = nums[outer] + nums[inner] + nums[left] + nums[right];
if (tmp_result == target) {
vector<int> tmp;
tmp.push_back(nums[outer]);
tmp.push_back(nums[inner]);
tmp.push_back(nums[left]);
tmp.push_back(nums[right]);
--right;
++left;
bool duplicate = false;
tmpres.insert(tmp);
} else if (tmp_result < target) {
++left;
} else {
--right;
}
}
}
}
auto it = tmpres.begin();
for(; it != tmpres.end(); it++)
result.push_back(*it);
return result;
}
};