您的位置:首页 > 其它

leetcode-1-15-16-18-Ksum

2016-03-01 13:20 405 查看
leetcode1—2 sum

给定一个target值,在一个序列里面找到两个和为target的数,按顺序返回它们的下标。给出的序列有且仅有一组这样的数。
解法:
题目假定只有一个解,大大降低了难度

(1)先排序再移动头尾指针缩小范围O(NlgN)
(2)哈希表、unordered_map O(N)
数组里没有重复数字

(1)先排序再移动头尾指针缩小范围:与只有一个解的方法一样,只是循环的时候不能break,O(NlgN)
(2)哈希表、unordered_map:也是和只有一个解的方法一样,只是循环的时候不能breakO(N)
数组里有重复数字

这个是2sum问题的一般情况,也是最为复杂的一种假设,不过可以转换为数组没有重复数组的情况求解,这是大概的思路。
(1)首先用一个新的vector存放去重之后的数组,因为最后要返回的是下标,所以要保存所有数字的下标,这样就要用一个链式哈希表存放数字的下标,可以用<int, list<int>>类型的unordered_map实现。O(N)
(2)接着用数组里没有重复数字的移动头尾指针的方法解决,得到所有的value pair。O(N)
(3)再根据这些value pair在链式哈希表里面找出所有的下标。O(
N2)
/*
用暴力搜索就要O(n)或者至少是O(nlgn),似乎会超时。
如果用hash的话就能保证O(n),注意要保存元素的下标,
所以用unordered_map,还要注意两个下标要按从小到大
的顺序。
因为结果只可能有一对下标,所以相同的数字最多有两个,
由于存入unordered_map的时候相同数字的下标会覆盖,
所以比较下标的时候保险就是一个用nums的下标,一个用查找
unordered_map返回的下标。
*/
/*
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> mymap;
vector<int> inds;
for (int i = 0; i < nums.size(); i++) {
mymap.insert(make_pair(nums[i], i));
}
for (int i = 0; i < nums.size(); i++) {
int gap = targ
893c
et - nums[i];
if (mymap.find(gap) != mymap.end()) {
if (i > mymap[gap]) {
inds.push_back(mymap[gap]);
inds.push_back(i);
break;
} else if (i < mymap[gap]){    //一定是两个不同的下标
inds.push_back(i);
inds.push_back(mymap[gap]);
break;
}
}
}
return inds;
}
};
*/
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
unordered_map<int, int> mymap;
vector<int> inds;
for (int i = 0; i < nums.size(); i++) {
mymap.insert(make_pair(nums[i], i));
}
for (int i = 0; i < nums.size(); i++) {
int gap = target - nums[i];
if (mymap.find(gap) != mymap.end()) {
if (i > mymap[gap]) {
inds.push_back(mymap[gap]);
inds.push_back(i);
break;
}
}
}
return inds;
}
};
int main(int argc, const char * argv[]) {
Solution s;
vector<int> n = {0,4,3,0};
vector<int> result = s.twoSum(n, 0);
for (int i = 0; i < result.size(); i++) {
cout << result[i] << " ";
}
cout << endl;
return 0;
}


leetcode15—3sum
在一个序列里面找出那三个数的和是0的,按顺序返回数字就可以了,不要求返回下标。结果可能会有多组
大概的思路就是将3sum转换为2sum,具体的做法:
首先排好序O(NlgN)并且去重(因为不需要返回下标)
遍历数组,寻找该次迭代要放在等号左边的数字;
确定好放在等号左边的数字之后,对之后的数字算2sum。

去重:
A + B + C = target   —>  B + C = target - A
target - A = B + X

target - B = A + X
已经放过等号左边的数字就不要再放在等号右边了,也就是说算2sum的时候不要考虑那些已经放过等号左边的数字。注意数组里可能有重复的数字。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> perm;
sort(nums.begin(), nums.end());
for (int i = 0; i < nums.size(); i++) {
//这里也是去重,target不会是重复的数字
while (i >0 && nums[i - 1] == nums[i]) {
i++;
}
int target = 0 - nums[i];
int left = i + 1, right = int(nums.size()) - 1;
while (left < right) {
if (nums[left] + nums[right] < target) {
left++;
} else if (nums[left] + nums[right] > target) {
right--;
} else {
vector<int> match = {nums[i], nums[left], nums[right]};
perm.push_back(match);
//去重,下一个一定是不一样的数
while (nums[left + 1] == nums[left]) {
left++;
}
while (nums[right - 1] == nums[right]) {
right--;
}
left++;
right--;
}
}
}
return perm;
}
};
int main(int argc, const char * argv[]) {
vector<int> test = {-4,-2,1,-5,-4,-4,4,-2,0,4,0,-2,3,1,-5,0};
Solution s;
vector<vector<int>> res = s.threeSum(test);
for (int i = 0; i < res.size(); i++) {
for (int j = 0; j < 3; j++) {
cout << res[i][j] << " ";
}
cout << endl;
}
return 0;
}


leetcode16 — 3sum closet
给定一个target,在一个序列里面找出三个数的和是最接近那个target的要求返回这三个数的和就可以了,给出的序列有且仅有一组这样的数。
想了一下,思路应该和3um的一样,只是要多一个全局变量来记录差值绝对值和对应的sum,最后返回sum就好了。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
sort(nums.begin(), nums.end());
int error = 2147483647;
int sum = 0;
for (int i = 0; i < nums.size(); i++) {
//这里也是去重,target不会是重复的数字
while (i >0 && nums[i - 1] == nums[i]) {
i++;
}
int t = target - nums[i];
int left = i + 1, right = int(nums.size()) - 1;
while (left < right) {
if (nums[left] + nums[right] < t) {
int less = t - nums[left] - nums[right];
if (less < error) {
error = less;
sum = nums[i] + nums[left] + nums[right];
}
left++;
} else if (nums[left] + nums[right] > t) {
int larger = nums[left] + nums[right] - t;
if (larger < error) {
error = larger;
sum = nums[i] + nums[left] + nums[right];
}
right--;
} else {
return target;
}
}
}
return sum;
}
};

int main(int argc, const char * argv[]) {
vector<int> test = {-1, 2, 1, -4};
int tartest = 1;
Solution s;
cout << s.threeSumClosest(test, tartest) << endl;
return 0;
}


leetcode18 — 4sum
给定一个target值,在一个序列里面找出4个sum为target的数字,按顺序返回数字就可以了,不要求返回下标,结果也是可能有多组。
采取跟3sum一样的思路,多加一层去重,具体做法:
首先排好序O(NlgN)(因为不需要返回)
遍历数组,寻找该次迭代要放在4sum等号左边的数字并且去重(第一次去重),确定好放在等号左边的数字之后,对之后的数字算3sum;
遍历数组,寻找该次迭代要放在3sum等号左边的数字并且去重(第二次去重),确定好放在等号左边的数字之后,对之后的数字算2sum;
参考博客还有一种做法,利用哈希,大致思路就是用两个pair代替4个数字,直接将4sum转成2sum:
首先枚举出所有可能的pair,用每一pair的sum作为key插入到链式哈希表(unordered_map)
中O( N2)
然后就可以用2sum的哈希解法来做了,注意最后还要判断2pair的下标是不是合法的,想(1,2,2,3)这种就是不合法的O(
N2)
#include <iostream>
#include <vector>
using namespace std;
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
vector<vector<int>> perm;
sort(nums.begin(), nums.end());
for (int i = 0; i < nums.size(); i++) {
//第一次去重
while (i >0 && nums[i - 1] == nums[i]) {
i++;
}
int target3 = target - nums[i];
for (int j = i + 1; j < nums.size(); j++) {
//第二次去重,注意j > i + 1而不是j > 1
while (j > i + 1 && nums[j - 1] == nums[j]) {
j++;
}
int target2 = target3 - nums[j];
int left = j + 1, right = int(nums.size()) - 1;
while (left < right) {
if (nums[left] + nums[right] < target2) {
left++;
} else if (nums[left] + nums[right] > target2) {
right--;
} else {
vector<int> match = {nums[i], nums[j], nums[left], nums[right]};
perm.push_back(match);
//去重,下一个一定是不一样的数
while (nums[left + 1] == nums[left]) {
left++;
}
while (nums[right - 1] == nums[right]) {
right--;
}
left++;
right--;
}
}
}
}
return perm;
}
};
int main(int argc, const char * argv[]) {
vector<int> n = {-1,0,1,2,-1,-4};
Solution s;
vector<vector<int>> res =  s.fourSum(n, -1);
for (int i = 0; i < res.size(); i++) {
for (int j = 0; j < 4; j++) {
cout << res[i][j] << " ";
}
cout << endl;
}
return 0;
}


用红黑树的做法就没仔细看了
参考这篇博客,写得很详细:Summary for LeetCode 2Sum, 3Sum, 4Sum, K Sum

leetcode31 — 3sum smaller要付钱,就先这样。

考察能否合理利用排序
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: