LeetCode 15 3Sum(尺取法或哈希)
2016-03-22 18:29
375 查看
题意:给出一个序列,求出这个序列里所有不重复的三元组{a,b,c},使得a+b+c=0。
思路:首先的想法是固定一个元素a,求剩下元素的和为-a的所有b,c组合。为了避免重复,排一次序,每次固定最小的元素,且每次固定的元素不重复,这样就可以用之前2 sum那道题的哈希做法了,时间复杂度为O(n^2),代码运行时间大约为110ms。
有没有更好的做法呢,可以注意到,之前我们已经排过一次序,那么问题转化为了在一个有序的序列上判断是否有两个元素的和等于一个给定的值。
解决这个问题的方法是尺取法,具体来说,就是取两个指针,一个指向序列头,一个指向序列尾,如果当前头尾指针指向的元素和大于给定值,那么尾指针向前移动一步,如果当前头尾指针指向的元素和小于给定值,那么头指针向后移动一步。如果与给定值相等,那么头尾指针各移动一步,为了防止重复,还要跳过与先前所指元素相等的元素。
这样做的好处是时间复杂度变为了严格的O(n),因为哈希可能会有冲突,所以时间上要比尺取法慢一些。
实测尺取法速度为50ms+。
附两份代码
尺取法:
hash:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int> > ans;
sort(nums.begin(), nums.end());
int len = nums.size();
for (int i = 0; i < len; i++) {
if (nums[i] > 0)
break;
if (i > 0 && nums[i] == nums[i-1])
continue;
unordered_map<int, int> um;
int target = -nums[i];
for (int j = i+1; j < len; j++) {
if (um[target-nums[j]] == 1) {
ans.push_back(vector<int> {nums[i], target-nums[j], nums[j]});
um[target-nums[j]] = 3;
}
um[nums[j]] |= 1;
}
}
return ans;
}
};
思路:首先的想法是固定一个元素a,求剩下元素的和为-a的所有b,c组合。为了避免重复,排一次序,每次固定最小的元素,且每次固定的元素不重复,这样就可以用之前2 sum那道题的哈希做法了,时间复杂度为O(n^2),代码运行时间大约为110ms。
有没有更好的做法呢,可以注意到,之前我们已经排过一次序,那么问题转化为了在一个有序的序列上判断是否有两个元素的和等于一个给定的值。
解决这个问题的方法是尺取法,具体来说,就是取两个指针,一个指向序列头,一个指向序列尾,如果当前头尾指针指向的元素和大于给定值,那么尾指针向前移动一步,如果当前头尾指针指向的元素和小于给定值,那么头指针向后移动一步。如果与给定值相等,那么头尾指针各移动一步,为了防止重复,还要跳过与先前所指元素相等的元素。
这样做的好处是时间复杂度变为了严格的O(n),因为哈希可能会有冲突,所以时间上要比尺取法慢一些。
实测尺取法速度为50ms+。
附两份代码
尺取法:
class Solution { public: vector<vector<int>> threeSum(vector<int>& nums) { vector<vector<int> > ans; sort(nums.begin(), nums.end()); int len = nums.size(); for (int i = 0; i < len; i++) { if (nums[i] > 0) break; if (i > 0 && nums[i] == nums[i-1]) continue; int target = -nums[i]; int front = i + 1, rear = len - 1; while (front < rear) { if (nums[front]+nums[rear] < target) front++; else if (nums[front]+nums[rear] > target) rear--; else { ans.push_back(vector<int> {nums[i], nums[front], nums[rear]}); front++; rear--; while (front < rear && nums[front] == nums[front-1]) front++; while (front < rear && nums[rear] == nums[rear+1]) rear--; } } } return ans; } };
hash:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int> > ans;
sort(nums.begin(), nums.end());
int len = nums.size();
for (int i = 0; i < len; i++) {
if (nums[i] > 0)
break;
if (i > 0 && nums[i] == nums[i-1])
continue;
unordered_map<int, int> um;
int target = -nums[i];
for (int j = i+1; j < len; j++) {
if (um[target-nums[j]] == 1) {
ans.push_back(vector<int> {nums[i], target-nums[j], nums[j]});
um[target-nums[j]] = 3;
}
um[nums[j]] |= 1;
}
}
return ans;
}
};
相关文章推荐
- Mootools 1.2教程 定时器和哈希简介
- C#获取哈希加密生成随机安全码的类实例
- C#计算字符串哈希值(MD5、SHA)的方法小结
- PowerShell中定义哈希散列(Hash)和调用例子
- PHP中创建和验证哈希的简单方法实探
- Perl 哈希的创建和引用介绍
- Perl 哈希Hash用法之入门教程
- perl哈希hash的常见用法介绍
- perl哈希的一个实例分析
- Go语言常见哈希函数的使用
- leetcode 179 Largest Number
- leetcode 24 Swap Nodes in Pairs
- leetcode 2 Add Two Numbers 方法1
- leetcode 2 Add Two Numbers 方法2
- leetcode----Longest Substring Without Repeating Characters
- [LeetCode]47 Permutations II
- [LeetCode]65 Valid Number
- [LeetCode]123 Best Time to Buy and Sell Stock III
- [LeetCode] String Reorder Distance Apart
- [LeetCode] Sliding Window Maximum