【3Sum】cpp
题目:
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)
代码:
class Solution { public: vector<vector<int> > threeSum(vector<int> &num) { std::vector<std::vector<int> > ret_vector; if (num.size() < 3) { return ret_vector; } // sort the vector std::sort(num.begin(), num.end()); // visit all the left side element of the current element const int target = 0; std::vector<int>::iterator end = num.end(); for (std::vector<int>::iterator i = num.begin(); i != end-2; ++i){ // ignore first duplicate i if ( i > num.begin() && *i==*(i-1)) continue; std::vector<int>::iterator j = i+1; std::vector<int>::iterator k = end-1; while (j<k){ const int tmp = *i+*j+*k; if ( tmp < target ){ ++j; while ( *j==*(j-1) && j<k ) ++j; } else if ( tmp > target ){ --k; while ( *k==*(k+1) && j<k ) --k; } else{ int tmp_triple[3] = {*i,*j,*k}; std::vector<int> tmp_vector(tmp_triple,tmp_triple+3); ret_vector.push_back(tmp_vector); ++j; --k; while( *j==*(j-1) && *k==*(k+1) && j<k ) { ++j; --k; } } } } return ret_vector; } };
Tips:
1. 先对传入的vector排序,然后从前向后遍历。原则是:包含*i元素,且满足条件的triple都加入到返回结果中
2. 这里比较困难的一点是排除重复的triple,大概想一想原则,一些极端的case只能试验出来了
另,在mac上编辑的,不知道为什么用数组初始化vector编译不通过,所以采用了比较麻烦的传参方式
===============================================
第二次过这道题,大体思路记得不太清,重新学习了一下“排序+双指针夹逼”方法
参考的blog:http://www.cnblogs.com/tenosdoit/p/3649607.html
class Solution { public: vector<vector<int>> threeSum(vector<int>& nums) { vector<vector<int> > ret; if ( nums.size()<3 ) return ret; std::sort(nums.begin(), nums.end()); for ( int i=0; i<nums.size()-2; ++i ) { // skip the duplicates elements if ( i>0 && nums[i]==nums[i-1] ) continue; Solution::TwoSum(ret, nums, i+1, 0-nums[i]); } return ret; } static void TwoSum(vector<vector<int> >& ret, vector<int>& nums, int begin, int target) { vector<int> tmp; int start = begin; int end = nums.size()-1; while ( begin<end ) { if ( nums[begin]+nums[end]<target ){ begin++; } else if ( nums[begin]+nums[end]>target ){ end--; } else { // add a triple tmp.push_back(nums[start-1]); tmp.push_back(nums[begin]); tmp.push_back(nums[end]); ret.push_back(tmp); tmp.clear(); // skip the duplicate elements begin++; while ( begin<end && nums[begin]==nums[begin-1] ) begin++; end--; while ( begin<end && nums[end]==nums[end+1] ) end--; } } } };
tips:
1. 先对数组进行排序
2. 固定一个元素,从其后面元素开始,采用两头夹逼的方式进行遍历。(为什么要两边夹逼?因为元素已经从小到大排序好了,向后移动begin可以增加两个元素的和,向前移动end可以减小两个元素的和;采用这样的方式,相当于进可往最大和靠,退可往最小值收,可以保证不漏)
3. 如果遇到重复的元素要跳过去,因为题中要求不能出现重复的triple。