原题地址:https://leetcode.com/problems/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:
- 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)
Subscribe to see which companies asked this question
原始解题思路:求三数之和,就是两数之和问题(#001 原题链接:https://leetcode.com/problems/two-sum/;解法:http://blog.youkuaiyun.com/lengyan110/article/details/51018896)的升级版,将三数中两数之和作为原来两数问题中的第二个数。
代码实现思路:通过三重循环实现,嵌套遍历a,b,c,将结果(a,b,c)放入vector<vector <int> >对象中,时间复杂度O(N^3)。显然时间复杂度太高。
优化思路:(错误范例)由于受 #001题的影响,为了避免同一个数的重复遍历,我采用了internal作为间隔值,分组求和,然而这种方法下时间复杂度仍为O(N^3),并发现在数组中有大量冗余数据时,这种方法会将每个冗余数据都遍历出来,如数组 (-1,-1,0,1),则会输出两次(-1,0,1),因为在数组中 -1 出现了两次,并且看到范例输出中输出结果有序,考虑到要进行排序。
1)大量冗余数据
如这个数组 (-7,2,5,-7,2,-7,3,4,)依次遍历需要很多时间。
如果提前排序为(-7,-7,-7,2,2,3,4,5)在遍历第一个-7之后,跳转到第3个-7可以节约不少时间,正是考虑到这个,这里我们选择在数组刚读入时就进行排序,以便于以后比较相邻数如果相同的话执行“跳过”的操作。
2)排序
如1)分析,我们调用sort函数完成排序。
到这里,我们还需要解决两个问题:1、如何降低时间复杂度? 2、如何“跳过”相同的数?
这里借鉴了 CheukyinYip的方法(https://leetcode.com/discuss/94215/my-easy-understanding-cpp-code),抛弃了#001时用的internal。
在a遍历循环中,取b.index=a.index+1,c.index=nums.size()-1
这样的好处在于在遍历b的时候可以自左向右的“跳过”相同的值,同时在另一端自右向左的“跳过”相同的值,而且不会导致覆盖。
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> results = {};
if (nums.size()<3)return results;
sort(nums.begin(), nums.end());
int right;
int tmp;
int left=0;
while (left <=nums.size()-3) {
right = left + 1;
int end = nums.size() - 1;
while(right < end) {
if ((nums[end] + nums[right] + (nums[left]))==0) {
vector<int> result = { nums[left],nums[right],nums[end]};
results.push_back(result);
tmp = nums[end]; while (end >= right && nums[end] == tmp)end--;
}
if ((nums[end] + nums[right] + (nums[left]))<0) { tmp = nums[right]; while (right <= end && nums[right] == tmp)right++; }
if((nums[end] + nums[right] + (nums[left]))>0){tmp = nums[end]; while (end >= right && nums[end] == tmp)end--; }
}
tmp = nums[left];
while(left <=nums.size()-1 && nums[left]==tmp)left++;
}
return results;
}
};