————————————————————————
我个人喜欢哈希表,还是挺好理解的,保存每次遍历过的值,遍历后面时,找下是否有符合要求的前值
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int> ret(2, 0);
int size = nums.size();
unordered_map<int, int> mp;
for (int i = 0; i < size; i++) {
if (mp.find(target-nums[i]) != mp.end()) {
ret[0] = mp[target-nums[i]];
ret[1] = i;
break;
}
mp[nums[i]] = i;
}
return ret;
}
};
跟上一题的区别是数组有序,当然也可以使用哈希表,不过因为是有序数组,我们还很容易想到双指针、二分法技巧。这里我用的是双指针,这个方法过于普遍,以至于针对这个题型扩展有了更多、更复杂的题。
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
int size = numbers.size();
int lo = 0, hi = size-1;
while (lo < hi) {
int sum = numbers[lo] + numbers[hi];
if (sum < target) lo++;
else if (sum > target) hi--;
else return {lo+1, hi+1};
}
return {-1, -1};
}
};
三数之和,这个比较复杂了,理论上是可以用哈希表保存所有两数之和,然后输出符合条件的三元数组,不过重复问题处理起来很头疼,有了上面双指针的基础,有序数组处理重复问题就很轻松了,这里稍微变通下就可以解决了。
先解决一个问题输出所有符合条件两数之和
vector<vector<int>> twoSum(vector<int>& numbers, int start, int target) {
sort(numbers.begin(), numbers.end());
vector<vector<int>> ret;
int size = numbers.size();
int lo = start, hi = size-1;
while (lo < hi) {
int sum = numbers[lo] + numbers[hi];
int left = numbers[lo], right = numbers[hi];
if (sum < target) {
while(lo < hi && numbers[lo] == left) lo++
}
else if (sum > target) {
while (lo < hi && numbers[hi == right) hi--;
}
else {
ret.push_back({numbers[lo], numbers[hi]});
//跳过重复元素
while (lo < hi && numbers[lo] == left) lo++;
while (lo < hi && numbers[hi == right) hi--;
}
}
return ret;
}
在此基础给出结果
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> ret;
sort(nums.begin(), nums.end());
int size = nums.size();
for (int i = 0; i < size; i++) {
vector<vector<int>> tupls = twoSum(nums, i+1, 0-nums[i]);
for (vector<int> tuple : tupls) {
tuple.push_back(nums[i]);
ret.push_back(tuple);
//跳过重复元素
while (i < size-1 && nums[i] == nums[i+1]) i++;
}
}
// n 为 3,从 nums[0] 开始计算和为 0 的三元组
return ret;
}
vector<vector<int>> twoSum(vector<int>& numbers, int start, int target) {
vector<vector<int>> ret;
int size = numbers.size();
int lo = start, hi = size-1;
while (lo < hi) {
int sum = numbers[lo] + numbers[hi];
int left = numbers[lo], right = numbers[hi];
if (sum < target) {
while(lo < hi && numbers[lo] == left) lo++;
}
else if (sum > target) {
while (lo < hi && numbers[hi] == right) hi--;
}
else {
ret.push_back({numbers[lo], numbers[hi]});
//跳过重复元素
while (lo < hi && numbers[lo] == left) lo++;
while (lo < hi && numbers[hi] == right) hi--;
}
}
return ret;
}
};
有了三数之和的基础,稍微变通下可以得出以下答案
class Solution {
public:
vector<vector<int>> nsum(vector<int>& nums, int target, int n, int start)
{
vector<vector<int>> ret;
int size = nums.size();
if (size < n || n < 2) return ret;
if (n == 2) {
int low = start, hi = size-1;
while (low < hi) {
int left = nums[low], right = nums[hi], sum = left + right;
if (sum < target) {
while(low < hi && left == nums[low]) low++;
}
else if (sum > target) {
while(low < hi && right == nums[hi]) hi--;
}
else {
ret.push_back({left, right});
//去掉重复的
while (low < hi && left == nums[low]) low++;
while (low < hi && right == nums[hi]) hi--;
}
}
} else {
for (int i = start; i < size; i++) {
vector<vector<int>> tuples = nsum(nums, target-nums[i], n-1, i+1);
//tuples是符合要求的二元数组,加上nums[i]就是想要的结果
for (vector<int> &tuple : tuples) {
tuple.push_back(nums[i]);
ret.push_back(tuple);
}
//num[i]不重复
while (i < size-1 && nums[i] == nums[i+1]) i++;
}
}
return ret;
}
vector<vector<int>> fourSum(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
return nsum(nums, target, 4, 0);
}
};
这样不管多少数之和都不在话下了