这里写目录标题
前言
本周分享一道双指针相关的算法题。作者水平有限,有任何问题欢迎在文章下方留言交流!
关键词:双指针。
题目
三数之和
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
力扣原题:https://leetcode-cn.com/problems/3sum
解法1-暴力破解
从头开始遍历,先确定第1个元素,然后遍历尝试与第2个元素组合,然后再对每一个组合遍历尝试第3个元素。
每找到一组符合条件的组合便与已找到的组合逐个做比较,若重复则去掉。
此法时间复杂度当然是相当之高的。
时间复杂度:O(n^3)
解法2-排序+双指针
上述暴力破解法显然存在巨大优化空间。我们可以使用双指针的方法来解决此问题。
算法具体流程:
-
特判:如果原数组长度
len
小于3,则直接返回 -
对数组进行排序
-
从头开始遍历数组,遍历的条件是
i<len-2
,且nums[i]
小于等于0-
若当前元素
nums[i]
与前一个元素nums[i-1]
相同,则跳过,防止得到重复结果 -
取左指针
L
为i+1
,右指针R
为len-1
,当左边界小于右边界时执行循环:- 若
nums[i]+nums[L]+nums[R] < 0
,则L=L+1
,如果nums[L]==nums[L-1]
,为防止结果重复,L继续往右移 - 若
nums[i]+nums[L]+nums[R] > 0
,则R=R-1
,如果nums[R]==nums[R+1]
,为防止结果重复,R继续往左移 - 若
nums[i]+nums[L]+nums[R] == 0
,则加入结果集,然后L=L+1
,R=R-1
,同时也需防止结果重复
- 若
-
代码实现:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
// result:结果集
vector<vector<int>> result;
// 获取原数组长度
int len = nums.size();
// 特判:如果原数组长度小于3,则直接返回
if(len<3) return result;
// 先对原数组进行排序
sort(nums.begin(), nums.end());
// 从头开始遍历数组,遍历的条件是i<len-2,且nums[i]<=0
for(int i=0;i<len-2 && nums[i]<=0;i++){
// 若当前元素与前一个元素相同,则跳过,防止得到重复结果
// 要记得限制i的大小,否则下标会越界
while(i>0 && i<len-1 && nums[i]==nums[i-1]) i++;
// L:左指针,初始化为当前元素+1位置
int L = i+1;
// R:右指针,初始化为末尾元素位置
int R = len-1;
// 开始循环查找符合条件的组合,当右指针小于或等于左指针时跳出循环
while(L<R){
if(nums[i]+nums[L]+nums[R] == 0){
// 若该组合符合条件,则加入结果集
result.push_back({nums[i], nums[L], nums[R]});
// 左指针往右移
L++;
while(L>0 && L<len-1 && nums[L] == nums[L-1]){
// 若左指针往右移时发现该元素与前一个元素相同,则继续往右移,防止得到重复结果
// 此处同样要记得限制L的大小,否则下标会越界
L++;
}
// 右指针往左移
R--;
while(R>0 && R<len-1 && nums[R] == nums[R+1]){
// 若右指针往左移时发现该元素与后一个元素相同,则继续往左移,防止得到重复结果
// 此处同样要记得限制R的大小,否则下标会越界
R--;
}
}else if(nums[i]+nums[L]+nums[R] < 0){
// 若该组合和小于0
// 则调整左指针往右移
L++;
while(L>0 && L<len-1 && nums[L] == nums[L-1]){
// 若左指针往右移时发现该元素与前一个元素相同,则继续往右移,防止得到重复结果
L++;
}
}else if(nums[i]+nums[L]+nums[R] > 0){
// 若该组合和大于0
// 则调整右指针往左移
R--;
while(R>0 && R<len-1 && nums[R] == nums[R+1]){
// 若右指针往左移时发现该元素与后一个元素相同,则继续往左移,防止得到重复结果
R--;
}
}
}
}
// 最后返回结果集
return result;
}
};
时间复杂度:
排序时间复杂度O(Nlog2(N))
遍历数组O(n)
双指针遍历O(n)
总体时间复杂度O(Nlog2(N))+O(n)*O(n),即O(n^2)。
空间复杂度:O(1)