K-sum 总结
2-sum
- 解法一: hash
从左往右扫描一遍,然后将数及对应坐标,存到map中。然后再扫描一遍即可,时间复杂度O(n)
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int,bool> mapping;
for(int i = 0; i < nums.size(); ++i)
mapping[nums[i]] = i;
vector<int> results;
for(int i = 0; i < nums.size(); i++){
int gap = target - nums[i];
if(mapping.find(gap) != mapping.end() && mapping[gap] > i){
results.push_back(i);
results.push_back(mapping[gap]);
break;
}
}
return results;
}
需要注意的是,对于含重复元素的序列,比如 numbers={ 2,2,5,6 },target = 4 的情况,可能大家会想 mapping 里面的 < 2, 1 > 会将< 2, 0 > 覆盖掉,这样是不是就不行了? 其实覆盖也没有关系,后面扫描时用的是第一个2,hash 获得的元素位置是第二个 2。
- 解法二:双指针扫描
将数组排序,然后双指针从前后往中间扫描,时间复杂度O(n*logn)
3-sum
解题思路:先排序,固定一个数,转化为 2-sum,利用双指针左右夹逼
//注意去重
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> results;
if(nums.size() < 3) return results;
sort(nums.begin(),nums.end());
const int target = 0;
for(int i = 0; i < nums.size()-2; ++i){
int j = i+1;
if(i > 0 && nums[i] == nums[i-1]) continue;
int k = nums.size() - 1;
while(j < k){
if(nums[i]+nums[j]+nums[k] < target){
++j;
while(nums[j] == nums[j-1] && j < k) ++j; //去重
}else if(nums[i]+nums[j]+nums[k] > target){
--k;
while(nums[k] == nums[k+1] && j < k) --k; //去重
}else{
results.push_back({nums[i],nums[j],nums[k]});
++j;
--k;
while(nums[j] == nums[j-1] && nums[k] == nums[k+1] && j < k) ++j; //去重
}
}
}
return results;
}
3-Sum Closest
与 3-Sum 解法类似,但不用考虑去重了。
int threeSumClosest(vector<int>& nums, int target) {
int results = 0;
sort(nums.begin(),nums.end());
int min_gap = INT_MAX;
for(auto a = nums.begin(); a!=prev(nums.end(),2); ++a){
auto b = next(a);
auto c = prev(nums.end(),1);
while(b != c){
int sum = *a + *b + *c;
int gap = abs(sum - target);
if(gap < min_gap){
min_gap = gap;
results = sum;
}
if(sum >target)
--c;
else
++b;
}
}
return results;
}