KSum问题是面试中常见的面试题,考察是否能够合理利用排序这个性质, 一步一步得到高效的算法。K sum的求和问题一般是这样子描述的:给你一组N个数字, 然后给你一个常数(比如 int target) ,目标是在这一堆数里面找到K个数字,使得这K个数字的和等于target。
2Sum
解决方法就是先从小到大排序,分别定义头尾指针,然后利用头尾指针找到两个数使得他们的和等于target。
vector<vector<int>> twoSum(vector<int>& nums, int target) {
vector<vector<int>> vec;
sort(nums.begin(),nums.end());
for (int i = 0; i < nums.size()-2;++i) {
int left = i;
int right = nums.size()-1;
while (left < right) {
int sum = nums[left] + nums[right];
if (sum > target) {
while (left < --right && nums[right] == nums[right+1]);
} else if (sum < target) {
break;
} else {
vector<int> temp = {nums[left],nums[right]};
vec.push_back(temp);
break;
}
}
}
return vec;
}
3Sum
3Sum问题可以转化为2Sum问题,将数组排序后,依次遍历数组的每个值val,目的是从剩余的数里面找2个数等于target-val。
vector<vector<int>> threeSum(vector<int>& nums, int target) {
int len = nums.size();
vector<vector<int>> vecs;
sort(nums.begin(),nums.end());
for (int i = 0; i < len-2; ++i) {
if(i > 0 && nums[i-1] == nums[i])
continue;
int left = i+1;
int right = len-1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum > target) {while(left < --right && nums[right] == nums[right+1]);}
else if (sum < target) {while(++left < right && nums[left] == nums[left-1]);}
else {
vector<int> temp = {nums[left], nums[right], nums[i]};
vecs.push_back(temp);
while(left < --right && nums[right] == nums[right+1]);
while(++left < right && nums[left] == nums[left-1]);
}
}
}
return vecs;
}
3Sum Closest
3Sum Closet 是 3Sum的变种版本,目的在于找到三个数之和与target最接近的组合。
int threeSumClosest(vector<int>& nums, int target) {
int len = nums.size();
sort(nums.begin(),nums.end());
int res = nums[0] + nums[1] + nums[2];
for (int i = 0; i < len-2; i++) {
if (i > 0 && nums[i] == nums[i-1]) {
continue;
}
int left = i+1;
int right = len-1;
while (left < right) {
int sum = nums[left] + nums[right] + nums[i];
if (abs(sum-target) < abs(res-target)) {
res = sum;
}
if (sum > target) {while(left < --right && nums[right+1] == nums[right]);}
else if (sum < target) {while(++left < right && nums[left] == nums[left-1]);}
else {
return sum;
}
}
}
return res;
}
4Sum
4Sum相比3Sum,无非多了一层循环,依然转化为2Sum问题求解。
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> vecs;
int len = nums.size();
sort(nums.begin(),nums.end());
for (int i = 0; i < len-3; ++i) {
if(i > 0 && nums[i] == nums[i-1])
continue;
if (nums[i]+nums[i+1]+nums[i+2]+nums[i+3] > target)
break;
if (nums[i]+nums[len-3]+nums[len-2]+nums[len-1] < target)
continue;
for (int j = i+1; j < len-2; ++j) {
if(j > i+1 && nums[j] == nums[j-1])
continue;
int left = j+1;
int right = len-1;
while (left < right) {
int sum = nums[i] + nums[j] + nums[left] + nums[right];
if (sum > target) {while(left < --right && nums[right] == nums[right+1]);}
else if (sum < target) {while(++left < right && nums[left] == nums[left-1]);}
else {
vector<int> temp = {nums[i],nums[j],nums[left],nums[right]};
vecs.push_back(temp);
while(left < --right && nums[right] == nums[right+1]);
while(++left < right && nums[left] == nums[left-1]);
}
}
}
}
return vecs;
}