双指针算法系列:一快一慢解决两数之和、三数之和与四数之和
创作时间:
作者:
@小白创作中心
双指针算法系列:一快一慢解决两数之和、三数之和与四数之和
引用
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;
}
};
小结:
对双指针算法的讲解就先告一段落啦,敬请期待下篇关于滑动窗口算法的介绍,欢迎各位大佬前来支持斧正!!!
热门推荐
柑桔早熟却不甜?多半是这些问题造成的!
别被骗了,这几种美国 FDA 认证都是假的!
接种狂犬疫苗后出现头痛发热是怎么回事
8小时睡眠制是错的?医生建议白天尽量不补觉,睡多久才算睡够呢
牛肉价格持续下跌,未来走势如何?
如何优化网络协议以提高传输速率
注意!2025 年,插头插座两项新国标实施,主要有这些技术变化!
身份证丢失后如何快速挂失与补办的详细指南与建议
上海芷江西“妈妈帮读书会”:从社区治理到个人成长的创新实践
蒙古语满语基因(蒙古语跟满文的区别)
变压吸附制氮在金属生产中的作用有哪些
USDT买卖交易是否在税收范围内
缓解嗓子干燥症状的有效方法与注意事项解析
吕祖《道德经》释义第二十一章
十二指肠溃疡怎么治疗
扁桃体炎 不要让它影响您的生活质量
化疗期间到底能不能运动?医生最想说的5个真相
来一杯鸡尾酒,调亮缤纷“宅“生活
山东滨州:让老人在熟悉的环境中乐享晚年
蒸笼纸对身体有害吗
大理民宿盈利模式深度解析:市场需求、成本控制与运营策略
《新乌托邦》首播:丧尸围城遇上韩国式幽默
糖醋土豆丝,口感酸甜爽口,做法简单易学(美味的家常菜)
高度近视怎么恢复眼睛视力
原单手表:正品还是仿货?揭开手表市场的真相
机器人应用实训项目(机器人)
《明月何时照我还》:思乡孤独与希望的情感共鸣探讨
分红型保险最后能拿到本金吗?万通保险专业解读分红险回报结构
汽车悬挂系统异响检查指南:减震器与球头故障排查
美龄宫:远东第一别墅的历史与文化