4Sum
Solution 1
作为NP问题复杂度讲解过程中常用的一个例子,4Sum注定是不会有特别理想的解法的。因此这里我就直接拿3Sum的双指针维护思路进行扩展,将第一个位置的顺序枚举改造成两层的顺序枚举。对应地可以进行推广到任意个数的和:前K-2个维度使用顺序遍历,后续使用双指针维护寻找后面两个数。
- 时间复杂度: O ( N 3 ) O(N^3) O(N3),其中 N N N为输入数字个数,对于任意个数的和检查,时间复杂度对应为 O ( N k − 1 ) O(N^{k - 1}) O(Nk−1)
- 空间复杂度: O ( N ) O(N) O(N),实际运行只占用状态维护变量,但是排序需要额外的空间占用
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
sort(begin(nums), end(nums));
return anySum(nums, target, 0, 4);
}
private:
vector<vector<int>> anySum(vector<int>& nums, int targetNow, int startNow, int kNow) {
vector<vector<int>> ans;
// 为空跳出或者不足要求跳出
if (startNow >= nums.size() || kNow > (nums.size() - startNow)) {
return ans;
}
// 只有两个,直接维护双指针
if (kNow == 2) {
return twoSum(nums, targetNow, startNow);
}
else {
for (int posX = startNow; posX < nums.size() - 2; posX ++) {
if (posX > startNow && nums[posX] == nums[posX - 1]) {
continue;
}
for (auto &ansSub : anySum(nums, targetNow - nums[posX], posX + 1, kNow - 1)) {
vector<int> temp = {nums[posX]};
for (auto num : ansSub) {
temp.push_back(num);
}
ans.push_back(temp);
}
}
}
return ans;
}
vector<vector<int>> twoSum(vector<int>& nums, int targetNow, int startNow) {
vector<vector<int>> ans;
// 两个指针
int posA = startNow, posB = nums.size() - 1;
while (posA < posB) {
int sum = nums[posA] + nums[posB];
if (sum == targetNow) {
ans.push_back({nums[posA], nums[posB]});
posA ++;
posB --;
// 指针去重
while (posA < posB && nums[posA] == nums[posA - 1]) {
posA ++;
}
while (posA < posB && nums[posB] == nums[posB + 1]) {
posB --;
}
}
else if (sum < targetNow) {
posA ++;
}
else {
posB --;
}
}
return ans;
}
};
Solution 2
Solution 1的Python实现
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
numsOrdered = sorted(nums)
return self.__anySum(numsOrdered, target, 0, 4)
def __anySum(self, numsOrdered, targetNow, startNow, kNow):
ans = list()
if startNow >= len(numsOrdered) or kNow > (len(numsOrdered) - startNow):
return ans
if kNow == 2:
return self.__twoSum(numsOrdered, targetNow, startNow)
else:
for posX in range(startNow, len(numsOrdered) - 2):
if posX > startNow and numsOrdered[posX] == numsOrdered[posX - 1]: continue
for ansSub in self.__anySum(numsOrdered, targetNow - numsOrdered[posX], posX + 1, kNow - 1):
ans.append([numsOrdered[posX]] + ansSub)
# print(posX, numsOrdered[posX], ansSub)
return ans
def __twoSum(self, numsOrdered, targetNow, startNow):
ans = list()
posA, posB = startNow, len(numsOrdered) - 1
while posA < posB:
sumNum = numsOrdered[posA] + numsOrdered[posB]
if sumNum == targetNow:
ans.append([numsOrdered[posA], numsOrdered[posB]])
posA += 1
posB -= 1
while posA < posB and numsOrdered[posA] == numsOrdered[posA - 1]: posA += 1
while posA < posB and numsOrdered[posB] == numsOrdered[posB + 1]: posB -= 1
elif sumNum < targetNow: posA += 1
else: posB -= 1
return ans