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.(给定含有n个元素的整型数组S,从数组S中找出所有的唯一三元组使得a+b+c=0成立)
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]
]
1.个人分析
可以先考虑一下二元组的情形,首先讲数组排序,然后利用“俩指针”方法进行相向遍历数组,找出所有使a+b=0的二元组。
2.个人解法
vector<vector<int>> threeSum(vector<int>& nums)
{
vector<vector<int>> res;
sort(nums.begin(), nums.end());
int left = 0, right = nums.size() - 1;
while(left+1 < right){
if((nums[left]+nums[left+1] + nums[right]) < 0)
++left;
else if((nums[left]+nums[left+1] + nums[right]) > 0)
--right;
else{
vector<int> vec;
vec.push_back(nums[left]);
vec.push_back(nums[left+1]);
vec.push_back(nums[right]);
res.push_back(vec);
++left;
--right;
}
}
return res;
}
该算法试图将两个元素指针作为一个整体从前向后进行移动,另一个指针则从后往前移动,不断地进行求和判断。但运行结果显示,大部分的测试用例返回结果有遗漏,所以这种思路无法解决问题。
3.参考解法
vector<vector<int>> threeSum(vector<int>& nums)
{
vector<vector<int> > res;
std::sort(nums.begin(), nums.end());
for (int i = 0; i < nums.size(); i++) {
int target = -nums[i];
int front = i + 1;
int back = nums.size() - 1;
while (front < back) {
int sum = nums[front] + nums[back];
// 找到符合等式要求的三个元素
if (sum < target)
front++;
else if (sum > target)
back--;
else {
vector<int> triplet(3, 0);
triplet[0] = nums[i];
triplet[1] = nums[front];
triplet[2] = nums[back];
res.push_back(triplet);
//遇到重复的元素继续移动front指针
while (front < back && nums[front] == triplet[1]) front++;
// 遇到重复的元素继续移动back指针
while (front < back && nums[back] == triplet[2]) back--;
}
}
// 跳过下一轮遍历的重复元素
while (i + 1 < nums.size() && nums[i + 1] == nums[i]) i++;
}
return res;
}
该算法也是运用了“俩指针”方法,并且将数组中的每个元素当做“锚点”进行遍历并同时查找其他两个符合条件的元素。
4.总结
起初想到了将两数相加和为0的解法迁移到该问题中来,但被“one pass”的算法思路给束缚了。之前一直都是贯彻从最简单直观的算法入手然后再进一步改进算法的思路进行的,现在发现有了先前的经验反而会限制思考。
PS:
- 题目的中文翻译是本人所作,如有偏差敬请指正。
- 其中的“个人分析”和“个人解法”均是本人最初的想法和做法,不一定是对的,只是作为一个对照和记录。