题目:
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]
]
描述:
题目个给出一个数组,若某三数字的和为0,则输出这三个数字。
分析:
没有数据范围的题目真心不想做
最简单直接的方法是三层循环遍历求出所有满足情况的解,然后利用set进行去重,时间复杂度O(n^3),空间复杂度为O(1),见代码一,
然而会超时...
首先探索本问题的简化版:
从一个有序数组(从左到右单调不减)中查找和为指定值的两个数
可以使用两个指针,一个指向最大项,一个指向最小项,若两个指针所指元素和大于目标值,即说明需要缩小两数和,则较大元素指针左移,若两元素和小于目标值,即说明需要增大两数和,较小元素的指针右移,若相等,则记录是两个元素。
本题目可以分解为两步:
1,固定一个数x
2,在剩余的数中查找和为-x的两个元素(刚好是上述简化版问题)
(然后思维还是没有打开,只想到了问题的简化版,却没继续往下想,太局限了...)
借鉴了网上的双循环做法,差点吐血了,思路完全一致,但是运行结果一直有问题...
感觉可以用lower_bound函数和upper_bound函数去跳过相同的数字,结果一直RE是什么鬼东西...
--------------------------------------
2019.04.02 8:40
又尝试了一遍,确实可以用lower_bound函数和upper_bound函数,不过感觉简化的不多(代码三)
代码一:(时间复杂度O(n^3))
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
set<vector<int>> result_set;
for (int i = 0; i < nums.size(); ++ i) {
for (int j = i + 1; j < nums.size(); ++ j) {
for (int k = j + 1; k < nums.size(); ++ k) {
if (nums[i] + nums[j] + nums[k] == 0) {
vector<int> temp;
temp.push_back(nums[i]);
temp.push_back(nums[j]);
temp.push_back(nums[k]);
sort(temp.begin(), temp.end());
result_set.insert(temp);
}
}
}
}
vector<vector<int>> result;
for (auto it = result_set.begin(); it != result_set.end(); ++ it) {
result.push_back(*it);
}
return result;
}
};
代码二:(时间复杂度O(n^2))
class Solution {
public:
vector< vector<int> > threeSum(vector<int>& nums) {
int len = nums.size();
//先排序
sort(nums.begin(), nums.end());
vector< vector<int> > result;
for(int i = 0; i < len; ++ i) {
int target = - nums[i], j = i + 1, k = len - 1;
while (j < k) {
int current = nums[j] + nums[k];
if (current < target) {
++ j;
} else if (current > target) {
-- k;
} else {
vector<int> temp;
temp.push_back(nums[i]);
temp.push_back(nums[j]);
temp.push_back(nums[k]);
result.push_back(temp);
int left = nums[j], right = nums[k];
while(j < k && nums[j] == left) {
++ j;
}
while(j < k && nums[k] == right) {
-- k;
}
}
}
while(i + 1 < len && nums[i + 1] == nums[i]) {
++ i;
}
}
return result;
}
};
代码三:(跟代码二基本完全一样)
class Solution {
public:
vector< vector<int> > threeSum(vector<int>& nums) {
int len = nums.size(), i = 0;
//先排序
sort(nums.begin(), nums.end());
vector< vector<int> > result;
while (i < len) {
int target = - nums[i], j = i + 1, k = len - 1;
while (j < k) {
int current = nums[j] + nums[k];
if (current < target) {
++ j;
} else if (current > target) {
-- k;
} else {
vector<int> temp;
temp.push_back(nums[i]);
temp.push_back(nums[j]);
temp.push_back(nums[k]);
result.push_back(temp);
int left = nums[j], right = nums[k];
while(j < k && nums[j] == left) {
++ j;
}
while(j < k && nums[k] == right) {
-- k;
}
}
}
int count = upper_bound(nums.begin(), nums.end(), nums[i]) -
lower_bound(nums.begin(), nums.end(), nums[i]);
i += count;
}
return result;
}
};