题目链接:https://leetcode.com/problems/two-sum/ (2-sum)
Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution.
Example:
Given nums = [2, 7, 11, 15], target = 9, Because nums[0] + nums[1] = 2 + 7 = 9, return [0, 1].
解题思路:对于2-Sum,笔者提供两种版本(二分 +线性查找),两种版本都是先排序。
线性查找,利用的是一种单调性,比容器盛水那道题(http://blog.csdn.net/u012717411/article/details/53406043)容易理解的多得多,复杂度O(n)。
二分版本O(nlogn)
struct node{
int val,pos;
friend bool operator < (node a,node b){
if(a.val == b.val) return a.pos < b.pos;
return a.val < b.val;
}
};
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
vector<int>ans;
node p[nums.size()];
for(int i = 0;i < nums.size();++ i){
p[i].val = nums[i];
p[i].pos = i;
}
sort(p,p+nums.size());
bool f = 1;
for(int i = 0;i < nums.size()&&f;++ i){
int l = i+1,r = nums.size();
while(l < r){
int m = (l + r) >> 1;
if(p[m].val == target - p[i].val) {
ans.push_back(p[i].pos);
ans.push_back(p[m].pos);
f = 0;
break;
}
if(p[m].val < target - p[i].val) l = m+1;
else r = m;
}
}
return ans;
}
};
线性查找O(n)
struct node{
int val,id;
friend bool operator <(node a,node b){
if(a.val == b.val) return a.id < b.id;
return a.val < b.val;
}
};
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) { //排序O(nlogn) + 查找O(n)
vector<int>ans;
node p[nums.size()];
for(int i = 0;i < nums.size();++ i){
p[i].val = nums[i];
p[i].id = i;
}
sort(p,p+nums.size());
int l = 0,r = nums.size() - 1;
while(l < r){
if(p[l].val + p[r].val == target){
ans.push_back(min(p[l].id,p[r].id));
ans.push_back(max(p[l].id,p[r].id));
break;
}
else if(p[l].val + p[r].val > target) r--;
else l++;
}
return ans;
}
};
题目链接:https://leetcode.com/problems/3sum/ (3-sum)
Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note: The solution set must not contain duplicate triplets.
For example, given array S = [-1, 0, 1, 2, -1, -4], A solution set is: [ [-1, 0, 1], [-1, -1, 2] ]
解题思路:有了2-sum的求解思路,很容易将3-Sum问题转换成2-Sum。
注意去重的处理,我一开始用二分查找,set去重,结果发现一直TLE;原因就是插入set次数太多,复杂度大于O(n^2log(n))!
这题必须要O(n^2)的算法才能过,卡set,也附出二分+set的版本:
版本一:二分 + set ( T L E )
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
set<vector<int>> tar;
sort(nums.begin(),nums.end());
bool f;int l,r;
for(int i = 0;i < nums.size();++ i){
for(int j = i+1;j < nums.size();++ j){
l = j+1,r = nums.size();
f = 0;
while(l < r){
int m = (l+r) >> 1;
if(nums[m] == -nums[i]-nums[j]) {f = 1;break;}
if(nums[m] < -nums[i]-nums[j]) l = m+1;
else r = m;
}
if(f){
tar.insert({nums[i],nums[j],-nums[i]-nums[j]});
}
}
}
return vector<vector<int>>(tar.begin(),tar.end());
}
};
版本二:不用set,自己剪枝去重即可,注意可能重复的原因(选取的第一个元素重复;两个加数重复;);
用set过不了的,可见这题比较卡时间!
2-Sum问题,用线性查找,总复杂度O(n^2)
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>>ans;
sort(nums.begin(),nums.end());
for(int i = 0;i < nums.size();++ i){
if(i && nums[i] == nums[i-1]) continue;//去重
//if(nums[i] > 0) continue;//剪枝
int tar = -nums[i];
int l = i+1,r = nums.size()-1;
while(l < r){
if(nums[l] + nums[r] == tar){
ans.push_back({nums[i],nums[l],nums[r]});
while(l < r && nums[l] == nums[l+1]) l++;//去重
while(l < r && nums[r] == nums[r-1]) r--;
l++;
r--;
}
else if(nums[l] + nums[r] < tar) l++;
else r--;
}
}
// return vector<vector<int>>(ans.begin(),ans.end());
return ans;
}
};
题目链接:https://leetcode.com/problems/4sum/ (4-Sum)
Given an array S of n integers, are there elements a, b, c, and d in S such that a + b + c + d = target? Find all unique quadruplets in the array which gives the sum of target.
Note: The solution set must not contain duplicate quadruplets.
For example, given array S = [1, 0, -1, 0, -2, 2], and target = 0. A solution set is: [ [-1, 0, 0, 1], [-2, -1, 1, 2], [-2, 0, 0, 2] ]
解题思路:4-Sum转成3-Sum,复杂度O(n^3),注意去重的处理!
参考代码
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>>ans;
sort(nums.begin(),nums.end());
for(int i = 0;i < nums.size();++ i){
if(i && nums[i] == nums[i-1]) continue;//去重
for(int j = i+1;j < nums.size();++ j){
if(j>=i+2 && nums[j] == nums[j-1]) continue;//去重
int l = j+1,r = nums.size() - 1;
while(l < r){
if(nums[i] + nums[j] + nums[l] + nums[r] == target){
ans.push_back({nums[i],nums[j],nums[l],nums[r]});
while(l < r && nums[l] == nums[l+1]) ++l;//去重
while(l < r && nums[r] == nums[r-1]) --r;
++l;
--r;
}
else if(nums[i] + nums[j] + nums[l] + nums[r] < target) l++;
else r--;
}
}
}
return ans;
}
};
K Sum 问题
问题描述
给你一组N个数字(比如 vector<int> num), 然后给你一个常数(比如 int target) ,我们的目标是在这一堆数里面找到K个数字,使得这K个数字的和等于target;
解题方法
3-Sum问题转化成2-Sum问题,4-Sum问题转成3-Sum问题,.....,K Sum 问题转换成 K - 1 Sum问题;
2-Sum的求解我们已知,线性查找O(n)。
复杂度
O(n^(k - 1))