原题地址:
https://leetcode.com/problems/3sum/description/
题目:
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] ]
解法:
这道题是2Sum的“进化版”,一开始我采用回溯法去解决,显然这是个极其不适合这道题目的方法,结果也如同猜测一样:TLE。这也给了我一个做这类题目的启发:当确定了结果中数组元素的个数时(特别是2个、3个这种),是肯定不会采用回溯法解决的。像Combination Sum那一类题目,结果中数组元素不确定时,才有可能使用回溯法。
既然是2Sum的进化版,我们就可以采用类似的办法去解决。我们可以先确定一个元素,然后再遍历剩下的元素,只要剩下的元素中有两个元素的和是我们确定元素的相反数时,这三个元素就是其中一个结果了。2Sum的时间复杂度为O(n),我们再在外面加一层循环,时间复杂度为O(n2),可以接受。下面是代码:
class Solution { public: vector<vector<int>> threeSum(vector<int>& nums) { vector<vector<int>> res; sort(nums.begin(), nums.end()); for (int k = 0; k < nums.size(); k++) { if (nums[k] > 0) break; if (nums[k] == nums[k - 1] && k > 0) continue; int i = k + 1, j = nums.size() - 1; while (i < j) { if (nums[i] + nums[j] + nums[k] == 0) { res.push_back({nums[k], nums[i], nums[j]}); while (i < j && nums[i + 1] == nums[i]) i++; while (i < j && nums[j - 1] == nums[j]) j--; i++; j--; } else if (nums[i] + nums[j] + nums[k] < 0) { i++; } else { j--; } } } return res; } };
下面是代码中的一些细节:
(1)首先要排序,然后最外的循环只需要循环到<=0的部分就可以了;
(2)为了避免出现重复,要加入
if (nums[k] == nums[k - 1] && k > 0) continue;
这个语句,比如[-4, -1, -1, 0, 1, 2]这个样例,假如不加这个语句,会出现两个[-1,0,1].
(3)下面这两个语句:
while (i < j && nums[i + 1] == nums[i]) i++; while (i < j && nums[j - 1] == nums[j]) j--;
想一下这个样例:[-2,0,0,2,2]
假如不加这两个语句,结果会有两个[-2,0,2]:因为最外一层循环为-2时,i=1,j=4和i=2,j=3都符合条件,而两者会出现重复,因此要忽略等于前一个元素值的元素。
总结一下(2)(3)这两点,可以发现这道题目会出现两种重复的原因,各自有不同的解决方法,这也是这道题困难的地方。
相关题目:
Two Sum:http://www.cnblogs.com/fengziwei/p/7501933.html