双指针算法(一)

目录

移动零

复写零

快乐数

盛水最多的容器

双指针与单调性结合

有效三角形的个数

查找总价格为目标值的两个商品

两数之和 Ⅱ - 输入有序数组 


双指针算法是通过定义两个指针不断单向移动来解决问题的一种算法。但双指针算法,是一个抽象的思想概念,可以用来解决数组划分、数组分块等问题。

它通常并不是真的定义两个指针,例如在 vector、string 中就经常通过下标来充当指针。

移动零

力扣链接:移动零

题目:给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

题目的意思:很明确,将所有非零元素移至数组最前面,数组中的零都放在数组偏后面的位置。

思路:定义两个 ‘指针’ cur 和 dest ,cur指针用来从左往右扫描遍历数组,一直指向扫描过的最后一个元素,dest指针一直指向遍历过的数组范围内最后一个不为零的位置。

具体做法:定义cur为0,dest为 -1(因为不知道第一个位置是否需要被交换),cur指针从左往右扫描数组,遇到等于0的元素直接跳过,遇到不等于零的元素,先让 dest 指针的位置加1,然后交换 cur 和 dest 两个位置的值后,两个指针再分别后移一位......如此循环直到最后cur扫描至数组最后一位。

此时数组就被划分为两个部分,因为dest指向的是遍历过的数组范围内最后一个不为零的位置,而扫描已经结束,所以 dest 指针指向的是最后一个不为 0 的位置,cur指针指向的是数组最后一个位置,两个指针中间的数就全是移动后的零。

代码详解(核心代码模式)

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

复写零

力扣链接:复写零

题目:给你一个长度固定的整数数组 arr ,请你将该数组中出现的每个零都复写一遍,并将其余的元素向右平移。

注意:请不要在超过该数组长度的位置写入元素。请对输入的数组 就地 进行上述修改,不要从函数返回任何东西。

思路:先根据 ‘异地’ 操作将数组进行按规则复写,然后优化为双指针下的 ‘就地’ 操作。

异地操作方法:两个指针 cur 和 dest 分别指向两个数组,一个原数组,一个与原数组空间相同的新数组。利用 cur 指针对原数组进行遍历,遇到非零元素,在新数组中按序拷贝,遇见0元素,就在新数组中连续拷贝两次。 

原地操作优化思路:先使用 ‘异地’ 操作的思想,找到最终两个指针复写结果的位置,从前往后完成复写!

具体做法:

(1)定义 cur 为0,dest 为 -1。cur 指针遍历数组,遇到不为0的数,dest向前移动一位,遇到0,dest 向前移动两位,当 dest 到达数组最后一个位置的时候,cur和dest的位置就是从后往前开始复写的位置。

(2)cur 指针开始向前走,遇到非零,dest就将这个数拷贝过去,dest前移一位;遇到0,dest就拷贝两个零,同时向前移动两位.....当cur移动到数组最开始的位置的时候,复写就结束了!

代码详解(核心代码模式)

class Solution {
public:void duplicateZeros(vector<int>& arr) {int cur = 0, dest = -1;int n = arr.size();//第一步:找到复写的位置while (dest <n){if (arr[cur] != 0)dest++;else if (arr[cur] == 0)dest += 2;if (dest >=n - 1)break;cur++;}//处理特殊情况if (dest==n)//dest指针越界,说明原数组倒数第二个位置为0{cur--;arr[n - 1] = 0;dest -= 2;}while (cur >= 0){if (arr[cur] != 0){arr[dest--] = arr[cur];}else if (arr[cur] == 0){arr[dest--] = arr[cur];arr[dest--] = arr[cur];}cur--;}}
};

注意点:当原数组的倒数第二个位置为0的时候,需要在循环结束后单独处理一下,否则就会造成数组越界! 

快乐数

力扣链接:快乐数

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

  • 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
  • 然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
  • 如果这个过程 结果为 1,那么这个数就是快乐数。

如果 n 是 快乐数 就返回 true ;不是,则返回 false 。

思路:快乐数定义的第二点非常重要,‘重复这个过程直到这个数字变为 1 ,也可能是 无限循环 但始终变不到1’。那么这个问题中,运算每进行一步,都可以看做链表往前走一步,其实可以抽象成链表成环问题,再使用 ‘快慢指针’ 来解决。

这里的快指针就是计算每位平方和后再将结果计算平方和,慢指针就只计算一次平方和......一直进行这样的操作,既然这个数字最后都会‘循环’,那么就是变成1循环还是其他多个数进行循环的问题了。

当快指针和慢指针相遇(相等)的时候,判断这个数是不是1,如果是1,这个数 n 就是快乐数,反之则不是。

代码详解(核心代码模式)

class Solution {
public:int Sumbit(int n){int sum = 0;while(n){int x = n % 10;sum += x*x;n /= 10;}return sum;}bool isHappy(int n) {//快慢指针int fast = n,slow = n;do{slow = Sumbit(slow);fast = Sumbit(Sumbit(fast));    }while(fast != slow);if(fast == 1)return true;elsereturn false;}
};

快指针和慢指针刚开始都等于这个数字 n,定义一个计算各位平方和的函数:慢指针调用1次,快指针调两次。然后使用 do...while 循环找到下次 快慢指针相等的值,判断这个值是否等于1即可。

盛水最多的容器

力扣链接:盛水最多的容器

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。

找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。

返回容器可以储存的最大水量。

说明:你不能倾斜容器。

思路:容器能盛水的最大高度是由两侧最低的柱子决定的!先计算出两侧开始的水的容量,设置为Max。利用双指针从两边到中间,高度较低一边的指针向中间移动,并重新计算容量,如果新容量大于初始的Max,就更新Max的值。两个指针相遇的时候,Max的值就是容器能容纳水的最大值。

代码详解(核心代码模式)

class Solution {
public:int V(vector<int>& height , int x , int y){return min(height[x],height[y]) * (y-x);}int maxArea(vector<int>& height) {int left = 0, right = height.size()-1;int Max = 0;while(left != right){int v = V(height,left,right);Max = max(v,Max);if(height[left] < height[right]){left++;}   elseright--;}return Max;}
};

双指针与单调性结合

有效三角形的个数

力扣链接:有效三角形的个数

给定一个包含非负整数的数组 nums ,返回其中可以组成三角形三条边的三元组个数。

前提:一组数中,两个较小的数相加大于较大的数,就能组成三角形(任意三边之和大于第三边的一组数能构成三角形的推论)

思路:先排序,保证不降序排列。从数组右侧开始固定最大的数,利用双指针(一个指针在最左边,另一个指针在固定数的左边),来确定固定的这个数的左半区间中能构成三角形的个数,然后向左更新这个被固定的数,重复上面的步骤,直至左半区间只有两个数为止循环结束。

确定左半区间中能构成三角形的个数:设固定的数位置为 tmp,则right的位置为 tmp -1 ,left 位置的值为 0。判断两个位置数相加后的结果与固定数的大小如果大于,说明两个指针 [ left 、right ) 之间的所有数,都能与 right、tmp形成三角形,则能形成三角形的个数将会增加 ( right - left )个如果小于等于,说明 left 这边的值不够大,将 left 指针再加1,重复上面的比较过程。当left指针和right指针相遇,或者两者的数大于 tmp 位置的数时结束本轮循环,更新固定数的位置继续上述过程。

代码详解(核心代码模式)

class Solution {
public:int triangleNumber(vector<int>& nums) {//只要两个小数相加大于大数,就能构成三角形sort(nums.begin(),nums.end());//先排序size_t sum = 0;//外层循环,固定一个最大的数for(int tmp = nums.size()-1; tmp >= 2; tmp --){int right = tmp-1;int left = 0;//利用双指针算法while(right != left){if(nums[left] + nums[right] > nums[tmp]){sum += (right-left);right--;}else{left++;}}}return sum;}
};

查找总价格为目标值的两个商品

两数之和 Ⅱ - 输入有序数组 

这两个题是一种思路,一个返回数。一个返回下边。但都是双指针思路、利用单调性来做题!

设定两个指针,一个在左边,一个在右边,因为数组是有序的,所以左边是最小的,右边是最大的,两个指针往中间移动,根据和与目标数值的大小关系,来确定指针的移动,最后两个指针停留于的位置,就是两个数的和等于目标值的位置。 

查找总价格为目标值的两个商品代码详解(核心代码模式)

class Solution {
public:vector<int> twoSum(vector<int>& price, int target) {vector<int> v1;int left = 0,right = price.size() - 1;while(left < right){if(price[left] + price[right] == target){v1.push_back(price[left]);v1.push_back(price[right]);break;}if(price[left] + price[right] < target){left++;}else{right--;}}return v1;}
};

两数之和 Ⅱ - 输入有序数组(核心代码模式) 

class Solution {
public:vector<int> twoSum(vector<int>& numbers, int target) {vector<int> v1;int left = 0,right = numbers.size()-1;while(left < right){if(numbers[left]+numbers[right]==target){v1.push_back(left+1);v1.push_back(right+1);break;}if(numbers[left] + numbers[right]>target){right--;}else{left++;}}return v1;}
};

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

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

相关文章

dockerfile,Docker镜像的创建

dockerfile&#xff1a;创建镜像&#xff0c;创建自定义的镜像。包括配置文件&#xff0c;挂载点&#xff0c;对外暴露的端口。设置环境变量。 docker的创建镜像的方式&#xff1a; 1、基于已有镜像进行创建。根据官方提供的镜像源&#xff0c;创建镜像&#xff0c;然后拉起容…

Linux主机自动注册NPS客户端(脚本化)

参考官方对API使用方法的定义&#xff1a;https://ehang-io.github.io/nps/#/ 1、首先必须要在配置文件中开启 auth_key 并配置一个合适的密钥 2、修改脚本中的可变量参数&#xff0c;以适配自己的环境 #!/bin/bash # 脚本使用说明&#xff1a;# 脚本名称&#xff1a;npc_cr…

+0和不+0的性能差异

前几日&#xff0c;有群友转发了某位技术大佬的weibo。并在群里询问如下两个函数哪个执行的速度比较快&#xff08;weibo内容&#xff09;。 func g(n int, ch chan<- int) {r : 0for i : 0; i < n; i {r i}ch <- r 0 }func f(n int, ch chan<- int) {r : 0for …

基于Microchip 光伏逆变器方案

小编杂谈新能源已经完成了至少5期的博文了&#xff0c;Boss告诉小编&#xff0c;如果还不介绍我们的产品和方案&#xff0c;黄花菜都凉了&#xff0c;所以小编这期博文就重点介绍一下Microchip在储能上的产品介绍&#xff0c;重点聊聊Microchip储能中使用的光伏逆变器的解决方案…

期末数组函数加强练习

前言&#xff1a;由于时间问题&#xff0c;部分题解取自网友&#xff0c;但都是做过的好题。 对于有些用c实现的题目&#xff0c;可以转化成c实现&#xff0c;cin看成c的读入&#xff0c;可以用scanf&#xff0c;输出cout看作printf&#xff0c;endl即换行符 开胃菜&#xff…

ES6原生音乐播放器(有接口)

视频展示 ES6音乐播放器 项目介绍 GutHub地址&#xff1a;GitHub - baozixiangqianchong/ES6_MusicPlayer: 音乐播放器 ES6_MusicPlayer 是基于JavaScriptES6Ajax等通过原生构建的项目。能够充分锻炼JS能力。 本项目有主页、详情页、歌单页面三部分组成 ├── assets&…

跨域的解决方式(java后端)

文章目录 一、跨域介绍1、什么是跨域2、为什么会产生跨域 二、简单请求和非简单请求1、简单请求2、非简单请求2.1、预检请求2.2、预检请求的回应2.3、浏览器的正常请求和回应 三、CrossOrigin注解1、CrossOrigin源码2、CorsRegistry方式3、CorsFilter过滤器4、自定义过滤器 一、…

Knowledge Distillation from A Stronger Teacher(NeurIPS 2022)论文解读

paper&#xff1a;Knowledge Distillation from A Stronger Teacher official implementation&#xff1a;https://github.com/hunto/dist_kd 前言 知识蒸馏通过将教师的知识传递给学生来增强学生模型的性能&#xff0c;我们自然会想到&#xff0c;是否教师的性能越强&…

【操作系统导论】内存篇——分页

引入 采用 「分段」 的方式&#xff0c;将空间切成 不同长度的分片&#xff0c;会出现 碎片化 问题&#xff0c;随着时间推移&#xff0c;分配内存会越来越困难。 因此&#xff0c;值得考虑「分页」的方法&#xff1a; 将空间分割成 固定长度的分片 &#xff1b; 将物理内存…

python列表的循环遍历

数据容器&#xff1a;一个可以存储多个元素的Python数据类型 有哪些数据容器&#xff1a;list&#xff08;列表&#xff09;&#xff0c;tuple&#xff08;元组&#xff09;&#xff0c;str&#xff08;字符串&#xff09;&#xff0c;set&#xff08;集合&#xff09;&#x…

第三方电脑小爱同学用快捷键唤醒

第三方电脑安装小爱同学-CSDN博客 请结合之前安装小爱同学的教程安装过程请提前取消windows更新 安装完成之后登录账号即可使用 Ahk2.0 下载地址&#xff1a;https://www.autohotkey.com/download/ahk-v2.zip 打开链接即可自动下载&#xff0c;下载后解压出来点击install.cmd安…

微信公众服务号升级订阅号

服务号和订阅号有什么区别&#xff1f;服务号转为订阅号有哪些作用&#xff1f;首先我们要知道服务号和订阅号有什么区别。服务号侧重于对用户进行服务&#xff0c;每月可推送4次&#xff0c;每次最多8篇文章&#xff0c;发送的消息直接显示在好友列表中。订阅号更侧重于信息传…

java飞翔的鸟游戏

A.准备工作 Bird类 Column类 BirdGame类 Ground类 B.中间过程 准备工作&#xff1a; 安装Java开发环境&#xff08;JDK&#xff09;。选择一个集成开发环境&#xff08;IDE&#xff09;&#xff0c;如Eclipse、IntelliJ IDEA或NetBeans。 创建项目&#xff1a; 在IDE中创建一个…

数据结构和算法(全)

1.了解数据结构和算法 1.1 二分查找 二分查找&#xff08;Binary Search&#xff09;是一种在有序数组中查找特定元素的搜索算法。它的基本思想是将数组分成两半&#xff0c;然后比较目标值与中间元素的大小关系&#xff0c;从而确定应该在左半部分还是右半部分继续查找。这个…

一文了解java中volatile关键字

认识volatile volatile关键字的作用有两个&#xff1a;变量修改对其他线程立即可见、禁止指令重排。 第二个作用我们后面再讲&#xff0c;先主要讲一下第一个作用。通俗点来说&#xff0c;就是我在一个线程对一个变量进行了修改&#xff0c;那么其他线程马上就可以知道我修改…

树莓派zero w入坑指南

树莓派zero w入坑指南 入坑契机 说起创客不得不提到开源硬件Raspberry Pi(树莓派)。它是一款基于ARM的微型电脑主板&#xff0c;以MicroSD卡为硬盘&#xff0c;提供HDMI和USB等外部接口&#xff0c;可连接显示器和键鼠。以上部件全部整合在一张仅比信用卡稍大的主板上&#x…

pytorch_lightning 安装

在安装pytorch-lightning时一定注意自己的torch是pip安装还是conda安装&#xff0c;pytorch_lightning 安装方式要与torch的安装方式保持一致&#xff0c;否则也会导致你的torch版本被替换。 正确安装方式&#xff1a; pip方式&#xff1a; pip install pytorch-lightning版本…

issue unit

The Issue Unit issue queue用来hold住&#xff0c;已经dispatched&#xff0c;但是还没有执行的uops&#xff1b; 当一条uop的所有的operands已经ready之后&#xff0c;request请求会被拉起来&#xff1b;然后issue select logic将会从request bit 1的slot中&#xff0c;选择…

第十二章 React 路由配置,路由参数获取

一、专栏介绍 &#x1f436;&#x1f436; 欢迎加入本专栏&#xff01;本专栏将引领您快速上手React&#xff0c;让我们一起放弃放弃的念头&#xff0c;开始学习之旅吧&#xff01;我们将从搭建React项目开始&#xff0c;逐步深入讲解最核心的hooks&#xff0c;以及React路由、…

0基础学java-day19(IO流)

一、文件 1 什么是文件 2.文件流 3.常用的文件操作 3.1 创建文件对象相关构造器和方法 package com.hspedu.file;import org.junit.jupiter.api.DynamicTest; import org.junit.jupiter.api.Test;import java.io.File; import java.io.IOException;/*** author 林然* vers…