【LeetCode】15_3Sum

题目

Given an array S of n integers, are there elements abc 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;
    }











  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值