题目
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:
- Elements in a triplet (a,b,c) must be in non-descending order. (ie, a ≤ b ≤ c)
- 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)
解析
其实就是另一个版本的2 sum。先排序,固定住第一个数字i,从后面的数字中去寻找和为-i的就可以了。需要注意的是:排序后的数字可能重复的很多,但是不可以去掉重复的,比如6,-3,-3这种组合,如果去掉重复数字就会出问题。
减少重复的几个环节是:
1.假设我们固定了数字i,那么只需要从i后面去查找剩下的数字就好了。前面的数字找到的肯定是重复的。
2.需要考虑连续几个数字都相等的情况。i+1和i的数字相等,那么直接跳过相等的。
3.即使这样还是可能有重复的,这个时候再用vector去重复。
我的代码如下:
//LeetCode 15
vector<vector<int>> threeSum_15(vector<int>& nums) {
sort(nums.begin(),nums.end());
vector<vector<int>> ret;
if (nums.size() < 3) return ret;
for (int i = 0;i<nums.size();i++)
{
if (i>0 && nums.at(i)==nums.at(i-1))
{
continue;
}
int target = nums.at(i);
int j = i+1;
int k = nums.size()-1;
while (j < k)
{
if (nums.at(j)+nums.at(k)+target == 0)
{
vector<int> tmp;
tmp.push_back(target);
tmp.push_back(nums.at(j));
tmp.push_back(nums.at(k));
ret.push_back(tmp);
j++;
}
else if (nums.at(j)+nums.at(k)+target > 0)
{
k--;
}
else
{
j++;
}
}
}
vector<vector<int>>::iterator iter;
iter = unique(ret.begin(),ret.end());
if(iter != ret.end())
{
ret.erase(iter,ret.end());
}
return ret;
1.第一个知识点是迭代器
vector <int>::iterator Iter;
for ( Iter = v1.begin( ) ; Iter != v1.end( ) ; Iter++ )
cout << " " << *Iter;
cout << endl;
2.另一个知识点是如何抹除数据
v1.erase( v1.begin( ) );
v1.erase( v1.begin( ) + 1, v1.begin( ) + 3 );
3.最后去掉重复数据
vector<vector<int>>::iterator iter;
iter = unique(ret.begin(),ret.end());
if(iter != ret.end())
{
ret.erase(iter,ret.end());
}
我们都知道unique的功能是去除相邻的重复元素(只保留一个),还有一个容易忽视的特性是它并不真正把重复的元素删除,不知道这个特性用起来就会出问题。unique只是把重复的元素放到容器的后面,而它本身会返回一个迭代器,只向这些元素的开始部分。因此要向真正删除这些元素,还是要“手工”处理一下。对于上面的例子,可以用vector窗口的erase.
代码可以通过,但是耗时120ms,属于耗时很多的人群。
来看看大神们的版本。
因为我们固定了i的值,例如-3,后面出现-3,6。表面上看有两个-3,似乎不能跳过这些-3.但其实第一个-3是固定的,没有参与后面的搜索,所以其实是应该跳过重复的值,这样就不会出现重复的vector了。
代码如下
vector<vector<int>> threeSum(vector<int>& num) {
vector<vector<int>> result;
if (num.size() < 3) return result;
sort(num.begin(), num.end());
const int target = 0;
auto last = num.end();
for (auto i = num.begin(); i < last-2; ++i) {
auto j = i+1;
if (i > num.begin() && *i == *(i-1)) continue;
auto k = last-1;
while (j < k) {
if (*i + *j + *k < target) {
++j;
while(*j == *(j - 1) && j < k) ++j;
} else if (*i + *j + *k > target) {
--k;
while(*k == *(k + 1) && j < k) --k;
} else {
result.push_back({ *i, *j, *k });
++j;
--k;
while(*j == *(j - 1) && *k == *(k + 1) && j < k) ++j;
}
}
}
return result;
}
在大神代码的启发下,我重改了一下,速度还可以。
vector<vector<int>> threeSum(vector<int>& nums) {
sort(nums.begin(),nums.end());
vector<vector<int>> ret;
if (nums.size() < 3) return ret;
for (int i = 0;i<nums.size();i++)
{
if (i>0 && nums.at(i)==nums.at(i-1))
{
continue;
}
int target = nums.at(i);
int j = i+1;
int k = nums.size()-1;
while (j < k)
{
if (nums.at(j)+nums.at(k)+target == 0)
{
vector<int> tmp;
tmp.push_back(target);
tmp.push_back(nums.at(j));
tmp.push_back(nums.at(k));
ret.push_back(tmp);
j++;
k--;
while (j<k && nums.at(k)==nums.at(k+1))
k--;
while (j<k && nums.at(j)==nums.at(j-1))
j++;
}
else if (nums.at(j)+nums.at(k)+target > 0)
{
k--;
while (j<k && nums.at(k)==nums.at(k+1))
k--;
}
else
{
j++;
while (j<k && nums.at(j)==nums.at(j-1))
j++;
}
}
}
return ret;
}