Problem: 15. 三数之和
首先我们来分析一下本题的思路
0
,而且呢这三个数的位置还要不一样[-1, 0, 1]
、[-1, 2, -1]
、[0, 1, -1]
,不过呢我们仔细看这个题意中的概念,又可以知道这些三元组还不可以重复,那么第一个和第三个我们就需要考虑到去重但是要如何去求解本题呢,怎么去找出这些三元组呢?找出之后又该如何去做一个去重的操作呢?我们马上进行算法原理分析
接下去我将通过分析算法原理来讲解本题该如何去进行求解
首先第一种,我们能想到的一定是暴力枚举
unordered_set
和Java中的Hashset
的话就可以知道如果我们将重复的数据扔到集合中的话就会去做一个自动去重的操作对于上面这种解法的代码就不给出了,读者可以自己去写写看
我们主要的话是来讲这种解法
left
指针指向i + 1
的位置,right
指针指向nums.size() - 1
的位置,然后通过这两个指针的遍历去寻找不同的三元组即可那有同学说,这在遍历的过程中要怎么去进行判断呢?
-a
即可,也就是这个数a的相反数所以我们来梳理一下这个逻辑
所以接下去呢我们还需要去处理一些【细节】方面的问题
left
和right
指针还需要继续去做移动的操作,因为我们是要找到这组数据中所有的三元组left++;right--;
left++
之后我们需要去判断当前所指的数字和上一个数字是否相同,如果出现了相同情况的话,就让left++
,跳过这个数。对于上面的这段逻辑我们需要放在【while】循环中执行,因为可能出现很多连续相同的数据while(nums[left - 1] == nums[left]) left++;
while(nums[right] == nums[right + 1]) right--;
i
做去重的逻辑,和left
是一致的// i的去重【防止越界】
i++;
while(nums[i] == nums[i - 1]) i++;
你认为这么就完了吗,那也太小瞧这道题了,毕竟也是力扣中的困难题
i
、l
、r
所指的数据都是一样的,所以在进行【while】循环的时候会一直地进行移动,此时就会造成l
超过r
或者r
超过l
的情况,不仅如此,i
在遍历的时候会碰到类似的情况所以我们应该把去重的逻辑做一个修改,可以起到防止越界的效果✔
left++;right--;
// left与right的去重【防止越界】
while(left < right && nums[left - 1] == nums[left]) left++;
while(left < right && nums[right] == nums[right + 1]) right--;
// i的去重【防止越界】
i++;
while(i < n && nums[i] == nums[i - 1]) i++;
以上就是【双指针】算法原理的分析,读者可以在阅读完之后试着自己写写看代码,很多细节的处理对代码能力的提升很有帮助
因为我们在遍历的时候, 每次去固定一个数a,然后下标为
i
,接着从[i + 1, n - 1]
的地方进行遍历,复杂度为: O ( n 2 ) O(n^2) O(n2)
因为没有去堆区申请任何空间,所以空间复杂度为 O ( 1 ) O(1) O(1)
以下是整体的代码展示
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
// 1.排序
sort(nums.begin(), nums.end());
// 2.利用双指针解决问题
vector<vector<int>> result;
int n = nums.size();
int i = 0;
while(i < n) // 固定a
{
// 若发现a > 0的话,则后面的nums[left] + nums[right]不会 < 0
if(nums[i] > 0) break;
int left = i + 1, right = nums.size() - 1, target = -nums[i];
while(left < right)
{
int sum = nums[left] + nums[right];
if(sum < target){
left++;
}else if(sum > target){
right--;
}else{
// 找到了,放入结果集
result.push_back({nums[i], nums[left], nums[right]});
left++;right--;
// left与right的去重【防止越界】
while(left < right && nums[left - 1] == nums[left]) left++;
while(left < right && nums[right] == nums[right + 1]) right--;
}
}
// i的去重【防止越界】
i++;
while(i < n && nums[i] == nums[i - 1]) i++;
}
return result;
}
};