您的位置:首页 > 其它

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+。

附两份代码

尺取法:

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;
}
};
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  leetcode 尺取法 哈希