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)
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的时候不要考虑那些已经放过等号左边的数字。注意数组里可能有重复的数字。
leetcode16 — 3sum closet
给定一个target,在一个序列里面找出三个数的和是最接近那个target的要求返回这三个数的和就可以了,给出的序列有且仅有一组这样的数。
想了一下,思路应该和3um的一样,只是要多一个全局变量来记录差值绝对值和对应的sum,最后返回sum就好了。
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)
用红黑树的做法就没仔细看了
参考这篇博客,写得很详细:Summary for LeetCode 2Sum, 3Sum, 4Sum, K Sum
leetcode31 — 3sum smaller要付钱,就先这样。
考察能否合理利用排序
给定一个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要付钱,就先这样。
考察能否合理利用排序
相关文章推荐
- iOS内存管理之自动释放池延迟销毁对象
- 171. Excel Sheet Column Number
- 在excel表中如何实现手动换行
- 【问题备忘】逐帧动画在Android5.0以上的问题
- python正则表达式(re)
- PopupWindow简单用法
- jdk动态代理与cglib动态代理
- 软件工程的文档是什么?
- 【POJ 2096】Collecting Bugs 概率期望dp
- 2016年实习生招聘信息
- ExtJS面向对象
- JDBC连接数据库的步骤
- Windows Server 2008活动目录学习
- Python中用format函数格式化字符串的用法
- iOS-数组,字典常用的字面量写法
- 自然数从何而来?
- 个人介绍
- js漂亮的弹出层
- 自我介绍
- 使用Markdown编辑器写博客