15. 3Sum
Given an array S of n integers, are there elements a, b, c in S such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.
Note: The solution set must not contain duplicate triplets.
For example, given array S = [-1, 0, 1, 2, -1, -4],
A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
]
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
}
};
解题思路:
-
自己的解题思路
一开始打算用两个指针技术,进行求解。但是遇到“下一步怎么走“问题。
最后用了一个重复查询的方法,进行搜索。
-
别人的解题思路
别人用的两个指针技术与我的不同,他是先确定一点,然而左右搜。我的则是先确定前后两点,然后再确定一点。
学习收获:
-
对于不重复的,可以采用pre-check技术,直接转到下一个不重复的值。
-
知道reserve()对运行时间的影响
-
熟悉了unique(),resize(),distance()[在<iterator>里面],以及erase()操作。
-
对于vector的erase() 只改变size,而且分2个版本:(1)删除1个值 (2)删除一个区间。
//操作1
auto it = unique(res.begin(), res.end());
res.resize(distance(res.begin(), it));
//操作2
auto it = unique(res.begin(), res.end());
res.erase(it, res.end());
附件:程序
1、自己的程序:
版本1:运用下标,进行搜索
vector<vector<int>> threeSum(vector<int>& nums)
{
bool myComp(vector<int> & a, vector<int> & b);
sort(nums.begin(), nums.end());
vector<int> temp(3);
vector<vector<int>> res;
auto size = nums.size();
if(size >= 3)
{
decltype(size) st = 0;
decltype(size) ed = size - 1;
while((ed - st) >= 1 && nums[st] <= 0 && nums[ed] >= 0)
{
while((ed - st) >= 1 && nums[ed] >= 0)
{
int wt = -(nums[st] + nums[ed]);
auto mid = find(nums.begin() + st + 1, nums.begin() + ed, wt);
if(mid != nums.begin() + ed)
{
temp[0] = nums[st];
temp[1] = *mid;
temp[2] = nums[ed];
res.push_back(temp);
}
--ed;
}
while((ed - st) >= 1 && nums[st] == nums[st + 1])
{
++st;
}
++st;
ed = size - 1;
}
}
auto it = unique(res.begin(), res.end());
res.resize(distance(res.begin(), it));
return res;
}
改进版1:改进后的程序,不再需要unique()操作
vector<vector<int>> threeSum(vector<int>& nums)
{
bool myComp(vector<int> & a, vector<int> & b);
sort(nums.begin(), nums.end());
vector<int> temp(3);
vector<vector<int>> res;
res.reserve(100);
auto size = nums.size();
if(size >= 3)
{
decltype(size) st = 0;
decltype(size) ed = size - 1;
while((ed - st) >= 1 && nums[st] <= 0 && nums[ed] >= 0)
{
while((ed - st) >= 1 && nums[ed] >= 0)
{
int wt = -(nums[st] + nums[ed]);
auto mid = find(nums.begin() + st + 1, nums.begin() + ed, wt);
if(mid != nums.begin() + ed)
{
temp[0] = nums[st];
temp[1] = *mid;
temp[2] = nums[ed];
res.push_back(temp);
}
while((ed - st) >= 1 && nums[ed] == nums[ed - 1])
{
--ed;
}
--ed;
}
while((ed - st) >= 1 && nums[st] == nums[st + 1])
{
++st;
}
++st;
ed = size - 1;
}
}
return res;
}
版本2:运用迭代器,进行搜索
vector<vector<int>> threeSum(vector<int>& nums)
{
vector<vector<int>> res;
if(nums.size() < 3)
{
return res;
}
sort(nums.begin(), nums.end());
auto p = nums.begin();
auto q = nums.begin() + 1;
for(; p < nums.end() - 1;)
{
while(q != nums.end())
{
int toFind = -(*p + *q);
auto pos = find(q + 1, nums.end(), toFind);
if(pos != nums.end())
{
res.push_back({ *p, toFind, *q });
}
if(toFind < 0)
{
break;
}
else
{
auto pre_q = q + 1;
while(pre_q != nums.end() && (*pre_q == *q))
{
++pre_q;
}
q = pre_q;
}
}
auto pre_p = p + 1;
while(pre_p < (nums.end() - 1) && (*pre_p == *p))
{
++pre_p;
}
p = pre_p;
q = p + 1;
}
return res;
}
版本3:使用Two-pointer
tech,但是无法通过所有的cases
vector<vector<int>> threeSum(vector<int>& nums)
{
vector<vector<int>> res;
if(nums.size() < 3)
{
return res;
}
sort(nums.begin(), nums.end());
auto p = nums.begin();
auto q = nums.end() - 1;
while(p < q)
{
int toFind = -(*p + *q);
auto pos = find(p + 1, q, toFind);
if(pos != q)
{
res.push_back({ *p, toFind, *q });
}
if(toFind < 0)
{
auto pre_q = q - 1;
while(pre_q != p && (*pre_q == *q))
{
--pre_q;
}
q = pre_q;
}
//对于toFind==0情况,讨论不足。
else
{
auto pre_p = p + 1;
while(pre_p != q && (*pre_p == *p))
{
++pre_p;
}
p = pre_p;
}
}
return res;
}
错误用例
Input:[-2,0,1,1,2]
Output:[[-2,0,2]]
Expected:[[-2,0,2],[-2,1,1]]
2、别人的程序
使用Two-pointers tech,可以通过。
vector<vector<int> > threeSum(vector<int> &num)
{
vector<vector<int> > res;
std::sort(num.begin(), num.end());
for(int i = 0; i < num.size(); i++)
{
int target = -num[i];
int front = i + 1;
int back = num.size() - 1;
while(front < back)
{
int sum = num[front] + num[back];
// Finding answer which start from number num[i]
if(sum < target)
front++;
else if(sum > target)
back--;
else
{
vector<int> triplet(3, 0);
triplet[0] = num[i];
triplet[1] = num[front];
triplet[2] = num[back];
res.push_back(triplet);
// Processing duplicates of Number 2
// Rolling the front pointer to the next different
number forwards
while(front < back && num[front] == triplet[1]) front++;
// Processing duplicates of Number 3
// Rolling the back pointer to the next different
number backwards
while(front < back && num[back] == triplet[2]) rear--;
}
}
// Processing duplicates of Number 1
while(i + 1 < num.size() && num[i + 1] == num[i])
i++;
}
return res;
}
比较简短版的
vector<vector<int>> threeSum(vector<int>& nums)
{
vector<vector<int>> triples;
triples.reserve(200);
sort(nums.begin(), nums.end());
int i = 0, last = nums.size() - 1;
while(i < last)
{
int a = nums[i], j = i + 1, k = last;
while(j < k)
{
int b = nums[j], c = nums[k], sum = a + b + c;
if(sum == 0) triples.push_back({ a, b, c });
if(sum <= 0) while(nums[j] == b && j < k) j++;
if(sum >= 0) while(nums[k] == c && j < k) k--;
}
while(nums[i] == a && i < last) i++;
}
return triples;
}