双指针算法系列:一快一慢解决两数之和、三数之和与四数之和
创作时间:
作者:
@小白创作中心
双指针算法系列:一快一慢解决两数之和、三数之和与四数之和
引用
CSDN
1.
https://m.blog.csdn.net/2303_81060385/article/details/143601155
本篇是双指针算法系列的最终篇,通过三个难度递增的题目,进一步强化对双指针算法的理解和运用。
相关题目及讲解
一. 两数之和
题目链接:LCR 179. 查找总价格为目标值的两个商品 - 力扣(LeetCode)
题目分析:
- 该题要求较为简单,只需要在数组中查找两个和为target的元素,并将他们储存在需要返回的数组中即可。
- 需要注意找到任一一对即可返回,无需返回多种情况。
思路讲解:
解法一:暴力解法(会超时)
很容易想到采用两个for循环直接逐个遍历的方式,符合要求即可直接返回。
class Solution {
public:
vector<int> twoSum(vector<int>& nums, int target) {
int n = nums.size();
for (int i = 0; i < n; i++) { // 第一层循环从前往后列举第一个数
for (int j = i + 1; j < n; j++) { // 第二层循环从 i 位置之后列举第二个数
if (nums[i] + nums[j] == target) // 两个数的和等于目标值,说明我们已经找到结果了
return {nums[i], nums[j]};
}
}
return {-1, -1};
}
};
解法二:对撞指针
基于解法一遍历思想的基础之上,我们对其通过减少遍历次数进行优化。
- 首先对数组进行排序
- 定义left=0,right=n-1,分别位于数组的左右两侧,代表最小和最大值。
- 用sum表示nums[left]与nums[right]的和,与target比较。
- 如果sum>target,则此时和过大,应该让right--
- 如果sum<target,则此时和过小,应该让left++
- 如果sum=target,插入返回的数组中直接返回即可
代码实现:
class Solution {
public:
vector<int> twoSum(vector<int>& price, int target) {
int n=price.size();
vector<int> ret;
int left=0,right=n-1;
while(left<right)
{
int sum=price[left]+price[right];
if(sum>target)
{
right--;
}
if(sum<target)
{
left++;
}
if(sum==target)
{
ret.push_back(price[left]);
ret.push_back(price[right]);
return ret;
}
}
return ret;
}
};
二. 三数之和
题目链接:15. 三数之和 - 力扣(LeetCode)
题目分析:
- 需要在一个数组内查找三个相加后和为0的元素
- 这三个元素不能重复,但元素的值可以相同
- 输出中不能包含内容相同的三元数组
思路讲解:
解法一: 暴力解法(会超时)
思路与两数之和大致相同,只是需要再嵌套一层for循环代表第三个数即可。
此时时间复杂度已经来到了恐怖的O(n^3),基本上是一定会超时的。
解法二:对撞指针
- 首先排序数组
- 在求解两数之和时,我们就采取了对撞指针的方法,那么此时是三数之和,我们只需要固定一个数,在该数右侧的区间内使用对撞指针即可。
- 使用for循环初始化一个i,那么i表示的就是我们需要固定的值,令left=i+1,right=n-1,重复两数之和的操作即可。只不过这次所求的target为-nums[i]。
- 在查找到符合条件的元素时,我们将nums[i],nums[left],nums[right]插入要返回的数组中,并进行去重操作:
- 由于每一轮插入成功后,都会令left++,right--,此时要考虑以下几种情况进行去重:
- 当nums[left]=nums[left-1]时,说明此处的left元素与上一个插入的相同,因此需要left++进行跳过。
- 当nums[right]=nums[right+1]时,说明此处的right元素与上一个插入的相同,因此需要right--进行跳过。
- 注意:循环和去重操作均需满足条件left<right!!!
- i的去重操作与上基本相同。
代码实现:
class Solution {
public:
vector<vector<int>> threeSum(vector<int>& nums) {
vector<vector<int>> ret;
sort(nums.begin(),nums.end());//排序
int n=nums.size();//总元素的个数
for(int i=0;i<n;)
{
int target=-nums[i];
if(target<0)
{
break;
}//说明元素全部大于0,不存在满足的情况
int left=i+1,right=n-1;
while(left<right)
{
int sum=nums[left]+nums[right];
if(sum>target)
{
right--;
}
else if(sum<target)
{
left++;
}
else
{
ret.push_back({nums[i],nums[left],nums[right]});
left++;
right--;
while(left<right&&nums[left]==nums[left-1])
{
left++;
}
while(left<right&&nums[right]==nums[right+1])
{
right--;
}
}
}
i++;
while(i<n&&nums[i]==nums[i-1])
{
i++;
}
}
return ret;
}
};
三. 四数之和
题目链接:18. 四数之和 - 力扣(LeetCode)
题目分析:
- 从数组内寻找4个加起来和为target的元素插入到需要返回的数组中
- 元素不可以重复
- 元素所代表的值可以重复
- 需要返回所有情况
思路讲解:
- 首先排序数组
- 基于三数之和的思想,我们只需要固定一个数,在其右侧的区间进行三数之和的对撞指针和去重操作即可。
- 需注意固定的这个数字在遍历的时候也需要去重。
代码实现:
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
sort(nums.begin(),nums.end());//排序
vector<vector<int>> ret;
int n=nums.size();
for(int i=0;i<n;)
{
for(int j=i+1;j<n;)
{
int left=j+1,right=n-1;
long long flag=(long long)target-nums[i]-nums[j];
while(left<right)
{
int sum=nums[left]+nums[right];
if(sum<flag)
{
left++;
}
else if(sum>flag)
{
right--;
}
else
{
ret.push_back({nums[i],nums[j],nums[left],nums[right]});//插入数据
left++;
right--;
while(left<right&&nums[left]==nums[left-1])
{
left++;
}
while(left<right&&nums[right]==nums[right+1])
{
right--;
}
}
}
j++;
while(j<n&&nums[j]==nums[j-1])
{
j++;
}
}
i++;
while(i<n&&nums[i]==nums[i-1])
{
i++;
}
}
return ret;
}
};
小结:
对双指针算法的讲解就先告一段落啦,敬请期待下篇关于滑动窗口算法的介绍,欢迎各位大佬前来支持斧正!!!
热门推荐
一生气就触发咳嗽?警惕5种疾病来“拜访”!
10部豆瓣9.0分以上的动画电影推荐,部部都是神作!
门徒效应:如何成为超级学习者
博尔特9秒58的纪录何时能打破?科学家:未来人类能跑进9秒
夜班族的痛:上班想睡觉,下班睡不着
墙面铺钉钢丝网(钢丝网的作用及防止开裂的办法)
代替绝缘胶布
如何按照劳动法合规裁员
壮观!长江江苏段出现鲢鳙阵,大鱼肥如猪,老渔政:30年未见此景
如何点石成金?张掖临泽给出参考答案
基本面选股:原理、指标与实践
中国易经风水大师领军人物,曾仕强已经离世,无量子隐居山林
【乒乓球教学】乒乓球技巧详解 业余选手提高乒乓球技巧的3要3不要
男子网购平板电脑,拆封后申请退货遭拒!一公司被罚
什么叫“神通”?
烦人的“过敏性鼻炎”又来了!学会这几招,有效预防少受罪
虚幻引擎 游戏开发基础
做完手术为什么要放两包盐?原理和注意事项全解析
外交家张骞:虽两次出使西域皆失败,但却开拓了丝绸之路
3D Mapping的实时交互技术:增强观众参与感
帮人按摩技巧:从准备工作到结束按摩的全程指南
恩次方梦境解码:长期做梦对健康的影响
蓝色调的柔和色彩 — 完美展现宁静优雅的视觉效果
扁平足怎么锻炼?6种有效方法改善足弓形态
无线键鼠选蓝牙还是2.4G:双方各有什么优缺点 一文读懂
数字中轴·文化过大年”圆满落幕:传统与科技交融,中轴线焕发新活力
FAA与eVTOL适航认证:历史、意义与影响(附文件包)
脑出血和脑中风有什么区别
像videos这样的视频内容,如何选择和观看?
虚拟机如何选磁盘类型