【算法专题】双指针算法

1. 移动零

题目分析

对于这类数组分块的问题,我们应该首先想到用双指针的思路来进行处理,因为数组可以通过下标进行访问,所以说我们不用真的定义指针,用下标即可。比如本题就要求将数组划分为零区域和非零区域,我们不妨定义两个指针cur和dest,cur不断向后遍历,dest则指向已处理区间内最后一个非零元素,当cur找到一个非零元素时,就把dest++并交换dest和cur对应的数组元素

那么在处理数组的过程中,数组被划分为了三块区域:

[0, dest]  [dest+1, cur] [cur+1, n-1]

分别代表:非零区域、零区域、未处理区域

当处理结束后只剩下非零区域和零区域了,而我们也实现了题目的要求,把数组中的所有元素都移动到数组末尾,且不改变其他元素的次序

实现代码:

class Solution {
public:void moveZeroes(vector<int>& nums) {int dest = -1, cur = 0; // 我们一开始并不知道dest的位置,暂时定义为-1while(cur < nums.size()) {if(nums[cur] == 0) {cur++;}else if(nums[cur] != 0) {dest++;swap(nums[dest], nums[cur]);cur++;}}}
};

2. 复写零

 1089. 复写零 - 力扣(LeetCode)

题目描述:

依据题意,数组中的零是会被重复写一遍的,那么一旦数组中有0,数组后面肯定就会有元素被覆盖掉,所以我们肯定是不能从前向后进行处理的。

为了保证不漏掉元素,我们应该要找到最后一个没有被覆盖的元素,然后把这个元素填到数组最后面,接着向前遍历,如果碰到的元素是非零,就填一次,如果是零就填两次,这样就实现了把所有的零都复写一遍,显然这个过程我们还是需要两个指针来帮助我们完成覆盖的操作。

所以我们接下来要实现的就是:

1. 找到最后一个“复写”的数

两个指针cur和dest,cur向后遍历,当碰到0时,dest向后移动两位,否则向后移动一位,这样,当dest指向数组末尾时,cur指向的位置就是数组中最后一个需要复写的元素位置了

2. 从前向后进行复写

在第一步处理之后,dest指向了数组末尾,cur指向了最后一个要复写的下标,cur和dest开始从后往前移动,并把cur元素覆盖到dest位置上,如果cur元素为0,就覆盖两次

3. 边界情况

一般情况下,上述的第一步处理中,dest是能正常移动到n-1位置的,但是存在这样一种情况:

当数组内容如上所示时,第一步的操作就会出现问题,dest指向了数组长度之外的位置,我们需要对这种情况进行特殊处理

实现代码:

class Solution {
public:void duplicateZeros(vector<int>& arr) {int cur = 0, dest = -1;int n = arr.size();while(cur <= n - 1) // 找到最后一个复写元素{if(arr[cur]) dest++;else dest += 2;if(dest >= n - 1){break;}cur++;}if(dest == n) // 对特殊情况进行处理{arr[n - 1] = 0;cur--;dest -= 2;}while(cur >= 0) // 从后往前进行复写{if(arr[cur]) arr[dest--] =arr[cur--];else{arr[dest--] = 0;arr[dest--] = 0;cur--;}}}
};

3. 快乐数

202. 快乐数 - 力扣(LeetCode)

题目分析

        依题意,对于一个正整数,如果每次将其替换为每个位置上数字的平方和,那么这个数最终可能为1或进入无限循环。事实上,这一点我们是可以证明的,首先给大家讲一下鸽巢原理:如果有n个巢穴,n+1只鸽子,那么至少有一个巢穴是有两只鸽子的。然后接下来解决本题,n的范围如上,如果将其最大值替换为每个位置上数字的平方和,2^31-1 的值为2,147,483,647,就算把这十位数换成9,999,999,999,按照这个算法,结果也只有810。

        也就是说,本题n取值范围内的所有数,经过处理得到的结果都不超过810,所以只要n经过811次变换,最后一定至少出现一次重复的元素,也就进入了循环。原因是:前810次n已经将所有变换的可能结果枚举了一遍,第811次的结果必定在前810次变换结果的集合之中,所以必定重复。

算法原理

        经过上述证明,我们清楚了n经过足够多次数的变换,只可能进入重复循环或变为1,而1的平方和恒为1,也算一个循环。所以我们要判断一个数是不是快乐数,只需要判断在循环中,这个数是不是1即可。

        这就要用到快慢指针算法了,fast指针一次移动两个单位,slow指针一次移动一个单位,则一旦fast和slow相遇,就说明已经在循环中了,此时仅需判断相遇时值是否为1即可。

代码如下:

class Solution {
public:// 进行变换int getsum(int n) {int sum = 0;while(n) {int tmp = n % 10;sum += tmp * tmp;n /= 10;}return sum;}bool isHappy(int n) {int fast = n, slow = n;do {// fast每次移动两个单位,slow移动一个单位fast = getsum(getsum(fast));slow = getsum(slow);} while(fast != slow);// 最后仅需判断相遇时值是否为1return fast == 1;}
};

4. 盛水最多的容器 

​​​​​​11. 盛最多水的容器 - 力扣(LeetCode)

题目解析

        根据题目示例,我们发现容器高度是由两端的柱子中较短的一根所决定的,设其高度为h,两根柱子的距离设为l,则我们要找的就是h*l最大的组合

算法原理

解法一 暴力解法

        从起始位置开始,将所有的位置都枚举一遍,最后肯定能找到盛水最多的容器,时间复杂度是O(n^2)但这样做肯定是会超时的,我们必须想一种更优秀的方法

解法二 双指针算法

        我们先用一个小区间来举例子,在题目解析中,我们看出了,容器高度由两端中较短的一方决定。在这个例子中,如果我们固定较短的柱子,移动另一端,可以发现,容器的容积是在减小的,问题在于:

1. 向内枚举,区间长度是一定减小的

2. 固定了短端,移动另一端,如果另一端比短端短,高度减小;就算比短端长,高度也不会变大

        所以趋势是:l一定减小,h不变或减小,v = h * l,则容积也必定减小!

        而如果我们固定较长的柱子,移动另一端,情况则有不同,如果短端找到更长的柱子,容器的容积是有可能增大的

        所以我们可以定义两个指针left、right在区间的0和n-1位置,找到短的一方,计算出当前容积,移动长的一方,这样我们只需要遍历数组一遍就能够找到最大值,时间复杂度为O(n)

class Solution {
public:int maxArea(vector<int>& height) {int l = 0, r = height.size() - 1;int h, w;int v = 0;while(l != r) {h = height[l] < height[r] ? height[l] : height[r];w = r - l;int tmp = h * w;v = tmp > v ? tmp : v;if(height[l] < height[r]) l++;else r--;}return v;}
};

5. 有效三角形的个数

 611. 有效三角形的个数 - 力扣(LeetCode)

题意分析:

        我们都知道,三角形的三条边满足任意两条边之和大于第三条边,但是还有一个更进一步的结论:假设a < b < c,则只要三个数满足a + b > c,就能保证任意两边之和大于第三条边。

        因此本题就转化为了,找到数组中满足 a < b < c 且 a + b > c 的三元组个数。

算法原理:

解法一:暴力解法

        用三层for循环列举出所有的三元组,然后判断是否满足构成三角形的条件,则时间复杂度:3*n^3,进行一下优化,如果我们先把数组排序,那么判断是否满足条件就只需要一次,时间复杂度为:n*logn + n^3,显然时间复杂度还是O(n^3),肯定是会超时的,我们需要想办法减小时间复杂度。

解法二:双指针算法

        在前面我们分析过了,要找的是满足 a < b < c 且 a + b > c 的三元组个数,和解法一中的优化一样,我们先将数组进行排序,则c肯定就在数组的末端找了,所以我们不妨先固定c,再找符合条件的a、b即可。

        可是如果我们还是用遍历的方式去找a和b,那时间复杂度根本就没有降低,还是O(n^3),所以必须换一个思路,既然 a < b ,我们不妨定义两个指针:left,right,分别从数组左右端移动,与上一道题类似的,我们要通过单调性来决定是移动left还是right!

        如果 a + b > c,因为数组排过序,是单调递增的,left++过程中是始终满足 a + b > c 的,由于本题求的是三元组个数,没必要进行left++了,直接right - left求个数即可。之后我们再进行right--,当left  == right时,说明这个c为最长边的情况列举完了,接着求下一个c为最长边的情况。

        如果 a + b <= c,因为数组排过序,是单调递增的,如果我们让right--,a + b 只能更小,因此只能让left++,直到 a + b > c 或 left == right。

代码如下:

class Solution {
public:int triangleNumber(vector<int>& nums) {int a, b, c;int max = nums.size() - 1;int cnt = 0;sort(nums.begin(), nums.end());while(max > 1){int left = 0, right = max - 1;while(left != right){a = nums[left], b = nums[right], c = nums[max];if(a + b > c){cnt += right - left;right--;}else left++;}max--;}return cnt;}
};

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

软件设计之Java入门视频(12)

软件设计之Java入门视频(12) 视频教程来自B站尚硅谷&#xff1a; 尚硅谷Java入门视频教程&#xff0c;宋红康java基础视频 相关文件资料&#xff08;百度网盘&#xff09; 提取密码&#xff1a;8op3 idea 下载可以关注 软件管家 公众号 学习内容&#xff1a; 该视频共分为1-7…

使用Python绘制堆积柱形图

使用Python绘制堆积柱形图 堆积柱形图效果代码 堆积柱形图 堆积柱形图&#xff08;Stacked Bar Chart&#xff09;是一种数据可视化图表&#xff0c;用于显示不同类别的数值在某一变量上的累积情况。每一个柱状条显示多个子类别的数值&#xff0c;子类别的数值在柱状条上堆积在…

zerotier-one自建根服务器方法五

一、简介 前面几篇文章已经写完了自己建立服务器的方法&#xff0c;今天写一下我在使用过程中遇到的问题和解决方法。 二、准备工作 准备一个有公网IP的云主机。 要稳定性、安全性、不差钱的可以使用阿里、腾讯等大厂的云服务器。 本人穷屌丝一枚&#xff0c;所以我用的是免…

最小代价生成树实现(算法与数据结构设计)

课题内容和要求 最小代价生成树的实现&#xff0c;分别以普利姆算法和克鲁斯卡尔算法实现最小代价生成树&#xff0c;并分析两种算法的适用场合。 数据结构说明 普利姆算法实现最小代价生成树的图采用邻接表存储结构&#xff0c;还有辅助数据结构&#xff0c;数组nearest&am…

统一视频接入平台LntonCVS视频监控平台具体功能介绍

LntonCVS视频监控平台是一款基于H5技术开发的安防视频监控解决方案&#xff0c;专为全球范围内不同品牌、协议及设备类型的监控产品设计。该平台提供了统一接入管理&#xff0c;支持标准的H5播放接口&#xff0c;使其他应用平台能够快速集成视频功能。无论开发环境、操作系统或…

【Android Kotlin】全网最全的Android Kotlin入门教程指南,入股不亏_android kotlin教程

Kotlin入门教程指南 前言 1.概述 1.1使用 Kotlin 进行服务器端开发1.2 使用 Kotlin 进行 Android 开发1.3 Kotlin JavaScript 概述1.4 Kotlin/Native 用于原生开发1.5 用于异步编程等场景的协程1.6 Kotlin 1.1 的新特性1.7 Kotlin 1.2 的新特性1.8 Kotlin 1.3 的新特性 2.开…

pandas中 groupby分组详解 1

引言 在一个使用 pandas 做数据分析的项目过程中&#xff0c;再次深刻理解了一下 pandas 中使用 groupby 进行分组的一些细节问题&#xff0c;以及对想要做的操作如何实现&#xff0c;在此记录&#xff1b; 问题 1&#xff1a;groupby 分组查看分组结果&#xff0c;以及重设分…

51单片机嵌入式开发:3、STC89C52操作8八段式数码管原理

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 STC89C52操作8八段式数码管原理 1 8位数码管介绍1.1 8位数码管概述1.2 8位数码管原理1.3 应用场景 2 原理图图解2.1 74HC573原理2.2 74HC138原理2.3 数码管原理 3 数码管程序…

Python 程序打印图案“G”(Python Program to print the pattern ‘G’)

在本文中&#xff0c;我们将学习如何使用星号和空格打印图案 G。给定一个数字 n&#xff0c;我们将编写一个程序&#xff0c;在 n 行或列上打印图案 G。 例子&#xff1a; 输入&#xff1a;7 输出&#xff1a; *** * * * *** * * * * *** 输入&…

Windows使用nxlog发送系统日志到Linux的rsyslog服务器

Windows使用nxlog发送系统日志到Linux的rsyslog服务器 前言一、IP地址规划及示意图二、在windows上安装及配置nxlog1.下载nxlog2.安装nxlog3.配置nxlog4.创建对应日志路径的文件夹 三、windows上启动nxlog服务四、在CentOS 7上配置日志存到指定位置文件1.编辑/etc/rsyslog.conf…

MySql Innodb 索引有哪些与详解

概述 对于MYSQL的INNODB存储引擎的索引&#xff0c;大家是不陌生的&#xff0c;都能想到是 B树结构&#xff0c;可以加速SQL查询。但对于B树索引&#xff0c;它到底“长”得什么样子&#xff0c;它具体如何由一个个字节构成的&#xff0c;这些的基础知识鲜有人深究。本篇文章从…

MATLAB engine for python调用m文件函数输出变量值python调用MATLAB函数混合编程

MATLAB engine for python调用m文件函数输出变量值python调用MATLAB函数混合编程 说明(废话)解决方案总结 说明(废话) python调用MATLAB函数&#xff0c;MATLAB函数实现在m文件&#xff0c;python直接调用MATLAB中的函数。 首先还是要安装好MATLAB engine python setup.py ins…

普通Java工程如何在代码中引用docker-compose.yml中的environment值

文章目录 一、概述二、常规做法1. 数据库配置分离2. 代码引用配置3. 编写启动类4. 支持打包成可执行包5. 支持可执行包打包成docker镜像6. docker运行 三、存在问题分析四、改进措施1. 包含environment 变量的编排文件2. 修改读取配置文件方式3. 为什么可以这样做 五、运行效果…

从文本到安全图像:自动提示优化防止不当内容生成

T2I生成技术已经得到了广泛关注&#xff0c;并见证了如GLIDE、Imagen、DALL-E 2、Stable Diffusion等大型生成模型的发展。尽管这些模型能够根据文本描述生成高质量的图像&#xff0c;促进了书籍插图、品牌标识设计、游戏场景创作等多种实际应用&#xff0c;但它们也被恶意用户…

ROS 2官方文档(基于humble版本)学习笔记(四)

ROS 2官方文档&#xff08;基于humble版本&#xff09;学习笔记&#xff08;四&#xff09; 2.客户端库使用colcon构建包&#xff08;package&#xff09;创建工作空间&#xff08;workspace&#xff09;构建工作空间执行测试&#xff08;tests&#xff09;导入环境&#xff08…

如何搜索查找ICLR论文

记录有几个查找顶级会议文章的网址&#xff0c;不止ICLR ICLR 2024 还会有visualization模式&#xff1a; ICLR 2024 virtual 这个网站也很棒 Paper Copilot ICLR 2024 当然还有一个用图表示各论文相关关系的网站&#xff1a; connected papers

入职字节外包2个月后,我离职了...

有一种打工人的羡慕&#xff0c;叫做“大厂”。 真是年少不知大厂香&#xff0c;错把青春插稻秧。 但是&#xff0c;在深圳有一群比大厂员工更庞大的群体&#xff0c;他们顶着大厂的“名”&#xff0c;做着大厂的工作&#xff0c;还可以享受大厂的伙食&#xff0c;却没有大厂…

Python应用开发——30天学习Streamlit Python包进行APP的构建(13)

st.chat_input 显示聊天输入窗口小部件。 Function signature[source]st.chat_input(placeholder="Your message", *, key=None, max_chars=None, disabled=False, on_submit=None, args=None, kwargs=None) Returns(str or None) The current (non-empty) value of…

排序——数据结构与算法 总结8

目录 8.1 排序相关概念 8.2 插入排序 8.2.1 直接插入排序&#xff1a; 8.2.2 折半插入排序&#xff1a; 8.2.3 希尔排序&#xff1a; 8.3 交换排序 8.3.1 冒泡排序&#xff1a; 8.3.2 快速排序&#xff1a; 8.4 选择排序 8.4.1 简单选择排序 8.4.2 堆排序 8.5 归并…

Docker:一、安装与卸载、配置阿里云加速器(Ubuntu)

目录 &#x1f341;安装docker&#x1f332;1、环境准备&#x1f332;2、安装docker Engine&#x1f9ca;1、卸载旧版、任何冲突的包&#x1f9ca;2、使用存储库安装&#x1f9ca;3、安装 Docker 包。&#x1f9ca;4、查询是否安装成功&#x1f9ca;5、运行hello-world镜像&…