Problem:
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]
]
这题和第一题TwoSum是比较类似的一道题,这次是寻找数组中任意三个数的和为0的组合,不能重复。我一开始的想法是用TwoSum的函数,然后先是用target=0减去nums数组中的一个数,然后再用TwoSum函数找出剩下的数中符合两个数加起来的和等于target,然后排序就完成了,后来用代码实现了这个想法:
Code:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> result;
if (nums.size() < 3) {
return result;
}
const int target = 0;
for (int i = 0; i < nums.size(); i++) {
int gap = target - nums[i];
vector<int> tmp = twoSum(nums, gap, i);
if (tmp.size() > 0) {
tmp.push_back(nums[i]);
sort(tmp.begin(), tmp.end());
if (result.size() == 0) {
result.push_back(tmp);
}
for (int j = 0; j < result.size(); j++) {
if (tmp == result[j]) {
break;
}
if (j == result.size() - 1) {
result.push_back(tmp);
}
}
}
}
return result;
}
vector<int> twoSum(vector<int>& nums, int target, int now) {
unordered_map<int, int> mapping;
vector<int> result;
for (int i = 0; i < nums.size(); i++) {
if (now == i) {
continue;
}
mapping[nums[i]] = i;
}
for (int i = 0; i < nums.size(); i++) {
if (now == i) {
continue;
}
const int gap = target - nums[i];
if (mapping.find(gap) != mapping.end() && mapping[gap] != i) {
result.push_back(nums[i]);
result.push_back(nums[mapping[gap]]);
break;
}
}
return result;
}
};
Code2:(LeetCode运行109ms)
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector< vector<int> > result;
if (nums.size() < 3) {
return result;
}
//夹逼法的前提是要排序,因为在进行前后比较需要判断是要哪一个下标往前,哪一个往后。
sort(nums.begin(), nums.end());
auto last = nums.end();
//attention: last - 2, 因为j+1会让下标越界。
for (auto i = nums.begin(); i < last - 2; i++) {
auto j = i + 1;
//跳过i迭代器表示的值重复的元素
if (i > nums.begin() && *i == *(i - 1)) {
continue;
}
auto k = last - 1;
//i,j,k表示三个数的迭代器,判断他们的和是否为0,固定i,如果比0大则表示k太大,k--,否则就是j太小,j++.
while(j < k) {
if (*i + *j + *k < 0) {
j++;
while(*j == *(j - 1) && j < k) {
j++; //跳过重复的元素
}
} else if (*i + *j + *k > 0) {
k--;
while(*k == *(k + 1) && j < k) {
k--;
}
} else {
result.push_back( {*i, *j, *k} );
//继续搜索下去一直到j<k
j++;
k--;
while(*j == *(j - 1) && *k == *(k + 1) && j < k) {
j++;
}
}
}
}
return result;
}
};
如果有更好的算法,希望大家和我分享!