Leetcode 15. 3Sum
题目
Given an array nums
of n integers, are there elements a, b, c in nums
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.
Example:
Given array nums = [-1, 0, 1, 2, -1, -4],
A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
]
Solution in O(n2)
直接上代码
class Solution {
public:
static vector< vector<int> > threeSum(vector<int>& nums) {
vector<vector<int> > re;
sort(nums.begin(), nums.end());
cout << "Init nums " << endl << "[ ";
for (auto n : nums) {
cout << n << " ";
}
cout << "]" << endl << endl;
int nums_size = nums.size();
for (int i = 0; i < nums_size - 2; ++i) {
cout << "i = " << i << endl;
int target = -nums[i];
int front = i + 1, back = nums_size - 1;
while (front < back) {
cout << "[1] front = " << front << " back = " << back << endl;
int sum = nums[front] + nums[back];
if (sum < target) {
while (nums[front+1] == nums[front] && front < back) front++;
front++;
} else if (sum > target) {
while (nums[back-1] == nums[back] && front < back) back--;
back--;
} else {
cout << i << " " << front << " " << back << endl;
re.push_back({nums[i], nums[front], nums[back]});
while (nums[front+1] == nums[front] && front < back) front++;
while (nums[back-1] == nums[back] && front < back) back--;
if (front < back - 1 && nums[front+1] + nums[back] > target) {
back--;
} else if (front < back-1) {
front++;
} else {
break;
}
}
cout << "[2] front = " << front << " back = " << back << endl;
}
while (nums[i+1] == nums[i] && i < nums_size - 2) i++;
}
return re;
}
};
分析
里边的cout, cerr
什么的都是注释,提交的时候是要去掉的。
这个解法是看Discuss看到的,大致学习了思想以后自己写了一份,应该所有的O(n2)都是类似于这样的解法。
若是暴力破解,那就很简单,三重循环嵌套起来,遍历每一个3个数的组合,得到了最终结果以后就去掉重复元素即可。这样的复杂度是O(n3),这个复杂度是过不了这个题的,因此必须降到O(n2)才行。
首先可以将给定的数组进行排序,也就是O(nlog(n))的复杂度(就按快速排序,STL的sort也是采用的快排)。然后从数组的开始到最后,依顺序选定一个数(假如是x),然后从其后边的所有数字中找两个数(假如是a和b),使得这两个数字的和是选定的那个数的相反数(-x=a+b,也就是三个数和为0了)。
由于我们已经将数组进行了排序,所以我们可以按照顺序寻找,给定两个标记front
和end
。分别指向选定元素的下一位和数组的最后一位。然后计算和,若是选的这两个数小了,那么就front++
,选择大的一个数字;若是选的大了,那么就end--
,选择较小的一个数。这样,我们增大或减小时的选择是唯一的,并且可以确定唯一的一组三元组。
我们可以分析,选定一个元素的复杂度为O(n-2) 也即O(n);每选定以后,要front
和end
分别从两边靠近,一共走过的是O(n)。因此总体为排序+二重循环,O(nlog(n)+n2)。