三数之和
思路:排序+双指针
时间复杂度: O ( n 2 ) O(n^2) O(n2),空间复杂度:O(logn)
分析:
- 首先,需要解决的问题是
无重复
,对于,这个问题我们可以用排序来解决,而sort
的时间复杂度为nlogn
,如此,我们每次枚举的n1, n2, n3
就满足n1 <= n2 <= n3
。 - 其次,如果对
nums
排序之后的算法的时间复杂度依然是 O ( n 3 ) O(n^3) O(n3)的,注意到,第一层for循环枚举0~n-1
,而第二、三层循环实际上是并列关系,因为nums是有序的,所以可以采用双指针的思想,即,第二、三层循环分别用从小到大和从大到小的指针替代。
- 伪代码
nums.sort()
for first = 0 ... n-1
if first == 0 or nums[first] != nums[first-1] then
// 第三重循环对应的指针
third = n-1
for second = first+1 ... n-1
if second == first+1 or nums[second] != nums[second-1] then
// 向左移动指针,直到 a+b+c 不大于 0
while nums[first]+nums[second]+nums[third] > 0
third = third-1
// 判断是否有 a+b+c = 0
check(first, second, third)
写法一:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int n = nums.size();
sort(nums.begin(), nums.end());
vector<vector<int>> res;
// 枚举 a
for (int i = 0; i < n; ++i) {
// 不重复
if (i && nums[i] == nums[i]) continue;
// 双指针:j、k
// 先固定右指针
int k = n-1;
int target = -nums[i];
for (int j = i+1; j < n; ++j) {
// 保证不枚举到重复的元素
if (j > i+1 && nums[j] == nums[j-1]) continue;
// 移动右指针的情况:左指针已经枚举到右指针了且此时 nums[j] + nums[k] 太大
while (j > k && nums[j] + nums[k] > target) --k;
/*
思考:为啥不考虑,nums[j] + nums[k] < target 的情况呢?
--> 要知道:k 是右指针一定是当前的最大值,所以在固定 k 的情况下
枚举的 nums[j] + nums[k] 是从小到大(下标j的值逐渐增加),
所以枚举一遍之后,如果没有出现等于target或者大于target的情况,
可以直接break, 那必然下次枚举时,下标 j 的值会变大。
*/
if (j == k) break;
if (nums[j] + nums[k] == target)
res.push_back({nums[i], nums[j], nums[k]});
}
}
return res;
}
}
写法二:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
int n = nums.size();
sort(nums.begin(), nums.end());
vector<vector<int>> res;
for (int i = 0; i < n-2; ++i) {
int x = nums[i];
if (i && x == nums[i-1]) continue;
if (x + nums[i+1] + nums[i+2] > 0) break;
if (x + nums[n-1] + nums[n-2] < 0) continue;
int j = i + 1, k = n - 1;
while (j < k) {
int s = x + nums[j] + nums[k];
if (s > 0) --k;
else if (s < 0) ++j;
else {
res.push_back({x, nums[j], nums[k]});
// 避免重复枚举
for (++j; j < k && nums[j] == nums[j-1]; ++j);
for (--k; j < k && nums[k] == nums[k+1]; --k);
}
}
}
return res;
}
};