基础算法--双指针算法

文章目录

  • 什么是双指针算法
  • 例题
    • 1.移动零
    • 2.复写零
    • 3.快乐数
    • 4.盛最多水的容器
    • 5.有效三角形的个数
    • 6.三数之和
    • 7.四数之和

在这里插入图片描述

什么是双指针算法

通常我们讲的双指针就是用两个指针,两个指针可以是快慢指针,解决成环的问题,也可以是指向收尾的两个指针,来减小时间复杂度。双指针算法里的指针也不止是指针,在数组中也可以是数组元素的下标,这里双指针是一种思想,并不是单单指的是指针。
接下来我们用几道例题来看看双指针算法。

例题

1.移动零

题目:移动零

在这里插入图片描述

样例输出输入:

在这里插入图片描述

这道题要我们将所有零移到数组的末尾并且不改变数组的的非零元素的相对位置,并且有一个前提就是不能开辟新的数组,对原数组进行操作。
解法一:暴力解法
思路:两层循环,一层循环找零,一层循环移动零到最后一个零的位置。
解法二:双指针
思路:首先对于上面这个题可以这样理解,可以把他划分为两个大区间,一个已经排除过零的区间和一个未排除过零的区间,已排除过零的区间又可以划分为非零区间和一个只含零的区间所以这三个区间。
在这里插入图片描述
所以我们可以用一个指针指向非零与零的区间的分界线,再用一个指针对数组进行遍历,如果遇到零就继续++,因为零本来就该在最后,如果遇到非零数就交换非零区间和零区间的分解线的数,这里分界线取的是第一个零的位置。这样,当我们遍历到最后一个数之后,未划分区间就没有了,只剩下非零区间和零区间了。
代码展示:

class Solution {
public:void moveZeroes(vector<int>& nums) {int cur=0;int dest=-1;while(cur<nums.size()){if(nums[cur]!=0){swap(nums[cur],nums[dest+1]);dest++;cur++;}else{cur++;}}}
};

2.复写零

题目:复写零

在这里插入图片描述

样例输入输出:

在这里插入图片描述

题目的意思就是让我们把数组当中的零在零之后复写但是复写之后数组的长度不变,所以后面数向后移动,所以最后就得到了样例输出。

思路:
首先我们先用异地操作模拟一下,开辟一个新的数组,然后进行拷贝,用两个指针,一个指针对原来的数组进行遍历,一个指针对新开辟的数组进行遍历,如果原来的数组遇到非零先判断新开辟数组是否越界,然后进行拷贝,两个指针同时向后移动,如果遇到零的话,还是先判断新开辟的数组是否越界,如果越界就停止,如果没越界拷贝在新开辟的数组中拷贝两个零,新开辟数组的指针向后移动两个单位,原来的数组向后移动一个单位。
上面讲的是异地操作,我们将异地操作优化为就地操作,首先我们考虑数组从左向右复写,首先这是不可能的,一个数组遍历一个数组进行复写的话会导致当我们复写的到零的时候后面的数已经被零覆盖了,所以遍历的时候后面会一直是零,复写就会一直复写零,所以这里我们考虑数组从后往前复写,如果从后往前复写的话我们就要考虑复写的最终位置,这里想到第一个办法就是双指针先就地模拟一遍异地操作,如果遇到零就+=2,如果遇到非零就+=1,这样用两个指针,最后一个指向末尾的元素就是就是需要拷贝的位置,另一个指针进行遍历数组并没有指向最后一个位置,所以这个位置指向的是复写的最后一个位置。通过模拟异地的复写我们已经找到最后一个复写的位置,现在只需要倒着复写即可,遇到零则复写两边,遇到非零则复写一遍。
代码展示:

class Solution
{
public:void duplicateZeros(vector<int>& arr) {//先找到最后一个复写位置,模拟异地操作int dest=-1;int cur=0;int n=arr.size();while(dest<n){if(arr[cur]!=0){dest++;}else{dest+=2;}if(dest>=n-1)break;cur++;}if(dest==n){arr[n-1]=0;dest-=2;cur-=1;}//从后向前完成复写操作while(cur>=0){if(arr[cur]!=0){arr[dest--]=arr[cur--];}else{arr[dest]=arr[cur];arr[dest-1]=arr[cur];dest-=2;cur-=1;}}}
};

3.快乐数

题目:快乐数

在这里插入图片描述

样例输入输出:

在这里插入图片描述

解法:
首先我们来看看什么事快乐数,如果各个位的平方相加,通过一系列重复操作之后,最后结果变为1,这就是快乐数,注意上面一句话很重要也就是无限循环,但可能不是1,这句话很重要。
首先我们用上面给出的两个例子来做样例:

在这里插入图片描述
上图上面样例的两个例子这样一看我们也就很熟悉了,这不是我们在链表做的链表带环的问题吗?判断链表是否带环只需要用一个快慢指针,如果两个指针,最后相遇则证明有环,如果两个指针没有相遇则证明最后没有环,这道题也很类似,这里的指针只需要抽象成操作的步骤,慢指针只操作一步,快指针操作两步,上面两种情况肯定是有环的,所以我们只需要判断两个指针相遇时的数是否是1,如果是1,则返回true,如果不是1,则返回false。

代码展示:

class Solution {
public://返回n这个数每一位上的平方和int bitsum(int n){int sum=0;while(n){int t=n%10;sum+=t*t;n/=10;}return sum;}bool isHappy(int n) {int slow=n;//slow等于第一个数int fast=bitsum(n);//fast等于第二个数while(fast!=slow){fast=bitsum(bitsum(fast));slow=bitsum(slow);}return slow==1;}
};

4.盛最多水的容器

题目:

在这里插入图片描述

样例输入输出:

在这里插入图片描述

题目意思很简单,这里的数组中的每个值代表的是高度,然后每个值对应的下标之差表示的是容器的宽度,宽度*高度就是我们水的最大容积。

解法一:暴力解法
暴力解法很简单,我们只需要用两个for循环每次for循环都记录一下这次的最大的容积,然后每次for循环完了之后,都对之前的容器的大小进行比较,如果新的容积大则更新容积,如果新的容积小,则不动。
解法二:双指针算法
首先我们先取首尾的指针,用下面的图讲解一下原理:
在这里插入图片描述
所以根据这个原理,向内取的话肯定是减小,所以这里我们每次肯定是小的高度进行–或者++。这里我们需要的变量就是两个首尾指针,然后还有一个记录最小值,最小值表示高度,因为高度是最小值决定的,因为向内取v是在不断减小的,所以这里我们每次更新的时候需要更新高度小的那个,更新高度大的那个会出现的情况可以看上面的图。
代码展示:

class Solution {
public://时间复杂度是O(N)int maxArea(vector<int>& height) {int tail=height.size()-1;int head=0;int v=0;while(head<tail){int Min=min(height[head],height[tail]);if(v<Min*(tail-head)){v=Min*(tail-head);}if(height[tail]<height[head]){tail--;}else{head++;}}return v;}
};

5.有效三角形的个数

题目:

在这里插入图片描述

输出输入样例:

在这里插入图片描述

解法一:暴力解法
这道题的暴力解法就是就是逐个遍历,将每一种情况遍历一遍,这道题由于不用去重,所以复杂程度直线下降,所以我们直接用三角形的判定的公式直接逐个情况判断就可以了,这里可以套三层循环,每种情况进行遍历,然后如果成立的话可以直接用一个count进行记录三角形成立的个数
解法二:双指针
步骤1:进行排序。
步骤2:排序之后,我们可以先固定最大的数,这里我们知道三角形满足a+b>c,这里c是最大的数,所以我们可以先固定最大的数,由于我们排序之后最大的数是最后一个数,所以这里我们可以直接取最后一个数为c,然后从c前面的数中取出a和b,但是a和b不是乱取的,我们先取最大的和最小的,也就是c前面的一个和第一个,如果最大的和最小的都能组成三角形,那么中间的组合肯定能组成三角形,因为中间的任何一个都比最小的大,所以这里可以直接计算三角形的个数的情况,三角形个数就是下标之差,接下来还有两种情况就是a+b==c或者a+b<c,这两种情况可以归为一种情况,就是left++,left向后移动,如果这种c的情况找完了,就可以将c–,继续找前面的情况满足的。
代码展示:

class Solution 
{
public:int triangleNumber(vector<int>& nums) {sort(nums.begin(),nums.end());int count=0;int left=0;int right=nums.size()-2;int c=nums.size()-1;while(c>=2){while(left<right){if(nums[left]+nums[right]>nums[c]){count+=(right-left);right--;}else{left++;}}//更新right和leftc--;left=0;right=c-1;}return count;}
};

6.三数之和

题目:

在这里插入图片描述

样例输出和输入:

在这里插入图片描述

这里我们可以直接看样例,题目的大概意思就是我们需要从数组中找三元组,并且三元组满足三元组的每个成员都是原数组中的不同位置的数,并且三元组不能有重复,三元组还要满足一个条件就是三元组之和加起来等于0。
解法一:暴力解法
这道题的难点就是在去重上,所以这道题我们可以用三个循环,然后把每个元素都遍历一遍用一个vector存储,最后把这个vector存在vectorvector中,如果是去重的话,我们可以直接用C++的一个容器就是unordered_set进行去重,最后直接把容器返回即可。

解法二:双指针
这里双指针和上一道题的双指针类似,还是需要固定一个数,这道题我们不用unordered_set进行去重,因为在算法题中可以用,但是在面试题中用unordered_set很可能会挂掉,所以我们海狮正常的用算法进行去重,首先我们海狮先排序,排序可以把相同的元素排在一起,排完序之后先固定一个数,我们先固定首元素,然后对首元素后面的数进行遍历,这里遍历只需要取首尾元素,这道题三数之和我们就转化为了两数之和,我们只需要求后面区间的数中存在两个数加起来等于前面这个数的相反数的组合即可,如果存在,则将其入到vector中,如果不存在则继续遍历,将固定的那个数往后移动,这里我们需要注意的细节是:我们后面的数加起来有三种情况:
第一种:大于前面的数,如果大于前面的数,可以直接将最大数–,因为这个数组被我们排成有序的了,所以不可能用left++,left++只会更大,所以应该是right–。
第二种情况:left+right=-a,这个情况直接入到数组中。
第三种情况:;left+right<-a,如果小于这个数,left++,如果right–只会更小。

接下来我们来谈谈去重的操作:
在这里插入图片描述
代码展示:

class Solution 
{
public:
vector<vector<int>> v;
vector<vector<int>> threeSum(vector<int>& nums)
{sort(nums.begin(), nums.end());int i = 0;while (i <= nums.size() - 2){int left = i + 1;int right = nums.size() - 1;while (left < right){vector<int> ret;int ret1 = nums[left];int ret2 = nums[right];if (nums[left] + nums[right] == -nums[i]){ret.push_back(nums[left]);ret.push_back(nums[right]);ret.push_back(nums[i]);v.push_back(ret);}if (nums[left] + nums[right] < -nums[i]){while (nums[left] == ret1){left++;if (left >= right){break;}}}else{while (nums[right] == ret2){right--;if (left >= right){break;}}}}int j = nums[i];while (nums[i] == j){i++;if (i > nums.size() - 1){break;}}}return v;
}  
};

7.四数之和

题目:

在这里插入图片描述

输出样例和输入样例:

在这里插入图片描述

四数之和可以参照三数之和,题目也是类似,我们需要找到四个数的和等于目标的target,但是这四个数的位置不能是一样的,

解法一:暴力解法
暴力解法很简单,只需要用四层循环把每种情况进行遍历一遍即可,最后再用容器进行去重操作。

解法二:双指针
这里和三数取和类似,我们只需要固定第一个数,对后面的数进行三数求和,然后将第一个固定的数逐渐往后遍历即可。

代码展示:

class Solution 
{
public:vector<vector<int>> v;vector<vector<int>> fourSum(vector<int>& nums, int target) {vector<vector<int>> ret;//排序int n=nums.size();sort(nums.begin(),nums.end());for(int i=0;i<n;){for(int j=i+1;j<n;){int left=j+1,right=n-1;long long aim=(long long)target-nums[i]-nums[j];while(left<right){int sum=nums[left]+nums[right];if(sum<aim)left++;else if(sum>aim)right--;else{ret.push_back({nums[left++],nums[right--],nums[i],nums[j]});//nums和nums的去重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;}
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/29988.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

window端口占用情况及state解析

背景&#xff1a; 在电脑使用过程中&#xff0c;经常会开许多项目&#xff0c;慢慢地发现电脑越来越卡&#xff0c;都不知道到底是在跑什么项目导致&#xff0c;于是就想查看一下电脑到底在跑什么软件和项目&#xff0c;以作记录。 常用命令 netstat -tuln &#xff1a; 使用…

Python3发送邮件如何添加附件?怎么配置?

Python3发送邮件的注意事项&#xff1f;如何配置Python3发邮件&#xff1f; Python3发送邮件时添加附件是一项常见的需求。无论是发送报告、图片&#xff0c;还是其他文件&#xff0c;掌握如何在邮件中添加附件至关重要。AokSend将详细介绍Python3发送邮件时如何添加附件&…

前端网站(二)-- 菜单页面【附源码直接可用】

菜单页面 开篇&#xff08;请大家看完&#xff09;&#xff1a;此网站写给挚爱&#xff0c;后续页面还会慢慢更新&#xff0c;大家敬请期待~ ~ ~ 轻舟所编写这个前端框架的设计初衷&#xff0c;纯粹是为了哄对象开心。除此之外&#xff0c;并无其它任何用途或目的。 此前端框…

JavaScript运行原理和执行过程

参考&#xff1a; https://www.cnblogs.com/hexrui/p/15939592.html 1、执行上下文栈&#xff08;调用栈&#xff09; GECGlobal Execution Context&#xff08;GEC&#xff09;被放入到ECS&#xff08;Execution Context Stack&#xff0c;简称ECS&#xff09;中 GEC开始执…

护眼灯哪些牌子好?一文刨析护眼灯怎么选择!

护眼灯哪些牌子好&#xff1f;护眼台灯作为对抗视力挑战的一种方法&#xff0c;逐渐赢得了众多家长的青睐。这些台灯利用尖端光学技术&#xff0c;发出柔和且无刺激的照明&#xff0c;有助于保护眼睛不受伤害。它们不但可以调节亮度和色温&#xff0c;打造一个舒适且自然的阅读…

upload-labs第十三关教程

upload-labs第十三关教程 第十三关一、源代码分析代码审计 二、绕过分析1&#xff09;0x00绕过a.上传eval.pngb.使用burpsuite进行拦截修改之前&#xff1a;修改之后&#xff1a;进入hex模块&#xff1a; c.放包上传成功&#xff1a; d.使用中国蚁剑进行连接 2&#xff09;%00绕…

【分布预测】DistPred:回归与预测的无分布概率推理方法

论文题目&#xff1a;DistPred: A Distribution-Free Probabilistic Inference Method for Regression and Forecasting 论文作者&#xff1a;Daojun Liang, Haixia Zhang&#xff0c;Dongfeng Yuan 论文地址&#xff1a;https://arxiv.org/abs/2406.11397 代码地址&#xff1a…

小白学RAG:大模型 RAG 技术实践总结

节前&#xff0c;我们组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、今年参加社招和校招面试的同学。 针对大模型技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备面试攻略、面试常考点等热门话题进行了深入的讨论。 汇总合集…

C++之模板(三)

1、缺省模板参数 可以将数据结构类型传递进来&#xff0c;比如vectop<T>&#xff08;如果没传就是默认&#xff09; 把vector当作类型参数来传递&#xff0c;从而使用它的接口然后适配出新的接口。实际上这个Stack称为适配器。有时候可能需要vector&#xff0c;但是又需…

【Python】AJAX

AJAX基础 一、AJAX1.1 概述1.2 XMLHttpRequest对象1.3 AJAX请求六部曲1.4 图解AJAX请求步骤 二、jQuery与AJAX2.1 jQuery.get()2.2 jQuery.getJSON()2.3 jQuery.post()2.4 jQuery.ajax() 三、Django使用AJAX3.1 请求类型3.2 PUT与PATCH的区别3.3 接收及响应JSON3.3.1 接收JSON3…

ui自动化selenium,清新脱俗代码,框架升级讲解

一&#xff1a;简化 1. 新建common 包 新建diver.py 封装浏览器驱动类 from selenium import webdriverclass Driver():"""浏览器驱动类定义 一个【获取浏览器驱动对象driver的方法】。支持多种类型浏览器"""def get_driver(self,browser_typ…

JimuReport 积木报表 v1.7.6 版本发布,免费的低代码报表

项目介绍 一款免费的数据可视化报表工具&#xff0c;含报表和大屏设计&#xff0c;像搭建积木一样在线设计报表&#xff01;功能涵盖&#xff0c;数据报表、打印设计、图表报表、大屏设计等&#xff01; Web 版报表设计器&#xff0c;类似于excel操作风格&#xff0c;通过拖拽完…

Python构造TCP三次握手、传输数据、四次挥手pcap数据包并打乱顺序

Python构造数据包&#xff0c;包含&#xff1a; TCP三次握手、 传输数据、 四次挥手 实现 随机乱序TCP数据包 from scapy.all import * from scapy.all import Ether, IP, TCP, UDP, wrpcap from abc import ABC, abstractmethod import random import dpkt from scapy.all…

6月18日(周二)美股行情总结:纳指七日连创新高,英伟达市值全球第一,苹果微软回落,油价七周最高

美国5月零售销售意外走软&#xff0c;尽管一众美联储官员均鹰派发声支持多等待通胀数据再做决策&#xff0c;市场仍抬升对年内降息两次的押注。标普500指数在七天里第六天上涨并再创新高&#xff0c;标普科技板块连续七天创新高、期间累涨8.6%&#xff0c;道指一周高位&#xf…

MySQL----慢查询日志

慢日志 MySQL可以设置慢查询日志&#xff0c;当SQL执行的时间超过我们设定的时间&#xff0c;那么这些SQL就会被记录在慢查询日志当中&#xff0c;然后我们通过查看日志&#xff0c;用explain分析这些SQL的执行计划&#xff0c;来判定为什么效率低下。 查看相关信息 show va…

iOS 18 终于更新了 iOS 隐藏 App 功能,这次是真的隐藏

如何锁定或隐藏 App 我们一起来看看 iOS 如何隐藏软件&#xff0c;下面是具体的操作步骤&#xff1a; iOS 隐藏 App 的第一步肯定是找到你想隐藏或锁定的应用程序&#xff0c;然后长按它的图标&#xff0c;在长按之后出现的选项中我们选择“需要 Face ID”。 然后在新弹出的选…

web版的数字孪生,选择three.js、unity3D、还是UE4

数字孪生分为客户端版和web端版&#xff0c;开发引擎多种多用&#xff0c;本文重点分析web端版采用哪种引擎最合适&#xff0c; 贝格前端工场结合实际经验和网上主流说法&#xff0c;为您讲解。 一、数字孪生的web版和桌面版 数字孪生的Web版和桌面版是数字孪生技术在不同平台…

Mamba: Linear-Time Sequence Modeling with Selective State Spaces论文笔记

文章目录 Mamba: Linear-Time Sequence Modeling with Selective State Spaces摘要引言 相关工作(SSMs)离散化计算线性时间不变性(LTI)结构和尺寸一般状态空间模型SSMs架构S4(补充)离散数据的连续化: 基于零阶保持技术做连续化并采样循环结构表示: 方便快速推理卷积结构表示: 方…

对SpringBoot入门案例的关键点

我们SpringBoot的入门案例中&#xff0c;即做了两个重要工作&#xff1a; 配置pom.xml文件写启动类 1.pom.xml依赖配置文件 ①帮助我们进行版本控制的父模块 <parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter…

Inpaint_2024软件最新版下载-inpaint下载安装2024-inpaint下载最新版本

众多使用者向我们证明了高效去除背景无关游客&#xff0c;只需要花费几秒钟在照片上选择不必要的对象或人员&#xff0c;剩下的交给Inpaint。准确来讲快速去水印&#xff0c;用Inpaint,选中水印&#xff0c;一键清除&#xff0c;还你一个干净整洁的图形。我们都知道快速去水印&…