【算法学习】-【双指针】-【复写零】
LeetCode原题链接:1089. 复写零
下面是题目描述:
给你一个长度固定的整数数组 arr ,请你将该数组中出现的每个零都复写一遍,并将其余的元素向右平移。
注意:请不要在超过该数组长度的位置写入元素。请对输入的数组 就地 进行上述修改,不要从函数返回任何东西。
- 示例 1:
输入:arr = [1,0,2,3,0,4,5,0]
输出:[1,0,0,2,3,0,0,4]
解释:调用函数后,输入的数组将被修改为:[1,0,0,2,3,0,0,4] - 示例 2:
输入:arr = [1,2,3]
输出:[1,2,3]
解释:调用函数后,输入的数组将被修改为:[1,2,3]
通过这道题可以获得的经验主要有如下两点:
- 实现“复写”之类的操作时,可以优先考虑从后往前进行复写,即多思考算法执行的顺序;
- 题目要求在原地对数组进行修改,但在分析时可以先按另外开辟空间的角度进行分析,然后再根据过程中进行操作的特点,通过指针模拟出在原数组中模拟出整个过程
下面是解题思路以及具体代码:
1、BF解法
根据题目描述,很容易想到这个暴力解法,也不涉及到有关双指针算法的运用,所以这里仅进行简单的陈述,对于想了解双指针解法的朋友可直接跳过~。
思路:从后往前遍历,每遇到一个0时,就从数组的倒数第二位开始,往自己的后一位去复写,即arr[n] = arr[n-1];直至到当前0的后一个位置。
如示例1中,从后往前第一个0的下标为4,那么当从后往前遍历到下标为4时,就从下标为6的位置(倒数第二位)开始依次往自己的后一位复写,直到下标为5(到当前0的后一个位置)。循环直至遍历完整个数组
具体代码为:
class Solution {
public:void duplicateZeros(vector<int>& arr) {int end = arr.size() - 1;int mov = end - 1;while(mov >= 0){if(arr[mov] == 0){while(end > mov){arr[end] = arr[end - 1];end--;}}mov--;end = arr.size() - 1;}}
};
2、双指针模拟容器
这是相对于解法1来说更好的解法,也是本文说明的重点。(PS:主要是对官方题解的理解总结)
我们可以先进行另开空间的过程分析,最后再通过指针在原数组上模拟。
那么从本题的要求来看,可以通过一个新的数组来进行数据的存储,即遍历原数组,遇到非0元素就将其放入一次进新数组中,遇到0就将其放入两次进vector中,直到新数组的大小等于或超过了(伏笔)原数组;
用示例1进行如上过程就为:

最后再将新数组对应原数组中的位置进行复写即可。
那么接下来的问题就是如何在原数组中模拟出这个过程。
-
首先是 “构建” 新数组:
说是构建,其实本质上是在原数组中找到新数组中最后一个数(或者说是用于复写原数组的第一个数),为复写做准备工作。
那么结合过程,我们可以这样找到这个数:
假设一个变量为mov用于表示将要放入新数组中的下一个数在原数组中的下标(也就是上图中的i),另一个变量size用于控制放入操作是否需要停止。接着遍历原数组,遇到非零元素mov和size一起++;遇到零元素mov++但size+=2,表示将0放了两次到新数组中;循环直至size大于等于原数组的大小。循环结束后mov的位置即为新数组的最后一个数(示例一中的4)在原数组中的位置的下一个位置,故让mov--指向新数组的最后一个数在原数组中的位置,准备进行复写 -
接下来是复写过程:
从原数组最后一个元素开始进行复写;用一个指针end指向它,接着以mov指针所对应的元素为判断依据,若是非零元素,则执行一次复写,复写完成后mov和end都往前移一位;若是零元素,则执行两次复写,复写完成后mov往前移一位,end往前移两位。循环执行如上过程直至复写完整个数组。 -
还有个坑:
上面说过,当新数组的大小等于或超过了原数组的大小时停止复写,等于原数组算是“正常”情况,新数组中零元素的个数为偶数个,即在原数组上复写时可以执行正确执行两次复写;但还有新数组的大小超过原数组的大小的情况,此时新数组中零元素的个数并不是偶数个,按照正常复写过程直接在原数组上复写会覆盖掉之前的数据,出现这种情况原因是最后需要复写两个零但空间只能再容纳一个零了,如这个测试用例:
[8,4,5,0,0,0,0,7]
当i = 5时,新数组中的size = 7,此时仅能再放入一个0,这意味着用双指针进行复写的时候,最后一个0只能复写一次
解决方法:
根据遇到0放入两次的操作,不符合条件跳出循环后,size的值是大于原数组的大小的(准确来说等于原数组大小+1),对这种情况进行特殊判断后先将最后一个元素进行复写,且mov和end都往前移一位后,再进行正常的复写即可。
完整的代码如下:
class Solution {
public:void duplicateZeros(vector<int>& arr) {int mov = 0;int size = 0;while(size < arr.size()){if(arr[mov] == 0){size+=2;}else{size++;}mov++;}mov--;int end;if(size == arr.size() + 1) //特殊判断{end = size - 2;arr[end] = 0;mov--;end--;}else{end = size - 1;}while(mov>= 0) {arr[end] = arr[mov]; //正常复写一次end--;if(arr[mov] == 0) //等于零再复写一次{arr[end] = arr[mov];end--; } mov--;}}
};
看完觉得有觉得帮助的话不妨点赞收藏鼓励一下,有疑问或看不懂的地方或有可优化的部分还恳请朋友们留个评论,多多指点,谢谢朋友们!🌹🌹🌹
相关文章:
【算法学习】-【双指针】-【复写零】
LeetCode原题链接:1089. 复写零 下面是题目描述: 给你一个长度固定的整数数组 arr ,请你将该数组中出现的每个零都复写一遍,并将其余的元素向右平移。 注意:请不要在超过该数组长度的位置写入元素。请对输入的数组 …...
【算法优选】双指针专题——叁
文章目录 😎前言🌳[两数之和](https://leetcode.cn/problems/he-wei-sde-liang-ge-shu-zi-lcof/)🚩题目描述:🚩算法思路:🚩算法流程:🚩代码实现 🎄[三数之和]…...
Java栈的压入、弹出序列(详解)
目录 1.题目描述 2.题解 方法1 方法2 1.题目描述 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序…...
RabbitMQ学习笔记(消息发布确认,死信队列,集群,交换机,持久化,生产者、消费者)
MQ(message queue):本质上是个队列,遵循FIFO原则,队列中存放的是message,是一种跨进程的通信机制,用于上下游传递消息。MQ提供“逻辑解耦物理解耦”的消息通信服务。使用了MQ之后消息发送上游只…...
PyTorch - 模型训练损失 (Loss) NaN 问题的解决方案
欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/133378367 在模型训练中,如果出现 NaN 的问题,严重影响 Loss 的反传过程,因此,需要加入一些微小值…...
8、Nacos服务注册服务端源码分析(七)
本文收录于专栏 Nacos 中 。 文章目录 前言确定前端路由CatalogController.listDetail()ServiceManager总结 前言 前文我们分析了Nacos中客户端注册时数据分发的设计链路,本文根据Nacos前端页面请求,看下前端页面中的服务列表的数据源于哪里。 确定前端…...
MySQL使用Xtrabackup在线做主从
1、主库上操作 1.1前提 172.16.11.2(主库) 172.16.11.4(从库) 在执行备份之前,确保数据库没有锁定,以避免备份期间的任何写操作。 确保主库上的 MySQL 服务器正在运行,以便备份数据的一致性。…...
scala基础入门
一、Scala安装 下载网址:Install | The Scala Programming Language ideal安装 (1)下载安装Scala plugins (2)统一JDK环境,统一为8 (3)加载Scala (4)创建工…...
【Java-LangChain:面向开发者的提示工程-5】推断
第五章 推断 推断任务可以看作是模型接收文本作为输入,并执行某种分析的过程。其中涉及提取标签、提取实体、理解文本情感等等。如果你想要从一段文本中提取正面或负面情感,在传统的机器学习工作流程中,需要收集标签数据集、训练模型、确定如…...
【C++】手撕vector(vector的模拟实现)
手撕vector目录: 一、基本实现思路方针 二、vector的构造函数剖析(构造歧义拷贝构造) 2.1构造函数使用的歧义问题 2.2 vector的拷贝构造和赋值重载(赋值重载不是构造哦,为了方便写在一起) 三、vector的…...
智能指针那些事
《Effective Modern C》学习笔记之条款二十一:优先选用std::make_unique和std::make_shared,而非直接new - 知乎...
Fiddler抓取手机https包的步骤
做接口测试时,有时我们需要使用fiddler进行抓包分析,那么如何抓取https包。主要分为以下七步: 1.设置fiddler选项:Tools->Options,按如下图勾选 2.下载并安装Fiddler证书生成器 下载地址:http://www.telerik.com/…...
idea没有maven工具栏解决方法
背景:接手的一些旧项目,有pom文件,但是用idea打开的时候,没有认为是maven文件,所以没有maven工具栏,不能进行重新加载pom文件中的依赖。 解决方法:选中pom.xml文件,右键 选择添加为…...
levelDB引擎
一、背景 1.1、影响磁盘性能的因素: 主要受限于磁盘的寻道时间,优化磁盘数据访问的方法是尽量减少磁盘的IO次数。磁盘数据访问效率取决于磁盘IO次数,而磁盘IO次数又取决于数据在磁盘上的组织方式。磁盘数据存储大多采用B树类型数据结构&…...
IM同步服务
设计概述 后台同步方案的设计就是数据存储结构的设计,如何快速体现“信息变化”,如何快速计算出“变化信息”。后台数据存储结构是由同步协议中同步契约决定的。 设计方案 该方案的同步是按照业务粒度来划分,只需要同步sdk要求同步的数据。…...
MySQL 运维常用脚本
常用功能脚本 1.导出整个数据库 mysqldump -u 用户名 -p –default-character-setlatin1 数据库名 > 导出的文件名(数据库默认编码是latin1) mysqldump -u wcnc -p smgp_apps_wcnc > wcnc.sql 2.导出一个表 mysqldump -u 用户名 -p 数据库名 表名> 导出的文件…...
ABC322刷题记
ABC322刷题记 T1.A A - First ABC 2。 妥妥的简单题…… 用find函数做就行。(如果不存在那个子串就返回-1,否则返回第一次出现位置) 注意题目中编号是从1开始的。 时间复杂度:O(log(n))。find函数有一定代价,我记…...
visual studio的安装及scanf报错的解决
visual studio是一款很不错的c语言编译器 下载地址:官网 点击后跳转到以下界面 下滑后点击下载Vasual Sutdio,选择社区版即可 选择位置存放下载文件后,即可开始安装 安装时会稍微等一小会儿。然后会弹出这个窗口,我们选择安装位…...
React生命周期
React的生命周期主要是指React组件从创建到销毁的过程,包括三个阶段:挂载期(实例化期)、更新期(存在期)、卸载期(销毁期) 挂载期: constructor(props&#…...
SpringBoot整合RocketMQ笔记
SpringBoot版本为2.3.12.Release RocketMQ对比kafka 学习链接 https://zhuanlan.zhihu.com/p/335216381 代码实战 https://www.cnblogs.com/RedOrange/p/17401238.html Centos安装rocketmq https://blog.csdn.net/chuige2013/article/details/123783612 RocketMQ详细配置与…...
51单片机控制8×8点阵显示汉字(上下左右滚动)
一、项目概述 本项目使用51单片机(如STC89C52)控制88 LED点阵,实现汉字的显示和上下左右滚动效果。通过动态扫描技术和字模数据管理,实现"中"、"国"等汉字的平滑滚动显示。 二、系统硬件设计 1. 硬件连接 ---…...
RexUniNLU中文NLP系统快速上手:Gradio界面快捷键与批量上传功能详解
RexUniNLU中文NLP系统快速上手:Gradio界面快捷键与批量上传功能详解 1. 系统概述与核心价值 RexUniNLU中文NLP综合分析系统是一个基于先进人工智能技术的自然语言处理工具,它能够帮助用户快速分析和理解中文文本的深层含义。这个系统最厉害的地方在于&…...
如何快速实现MongoDB实时数据同步:mongo-connector完整指南
如何快速实现MongoDB实时数据同步:mongo-connector完整指南 【免费下载链接】mongo-connector MongoDB data stream pipeline tools by YouGov (adopted from MongoDB) 项目地址: https://gitcode.com/gh_mirrors/mo/mongo-connector MongoDB作为广泛使用的N…...
不只是跑波形:用ModelSim+Quartus做一次完整的FPGA功能验证(以边沿检测模块为例)
不只是跑波形:用ModelSimQuartus做一次完整的FPGA功能验证(以边沿检测模块为例) 当你在Quartus中点击"Start Simulation"按钮时,是否曾思考过:仿真究竟是为了看漂亮的波形图,还是为了验证设计的正…...
ST单片机Flash实测:擦写80万次不坏的存储技巧大公开
ST单片机Flash存储实战:突破80万次擦写寿命的工程技巧 在消费电子和物联网设备开发中,Flash存储的寿命问题常常成为产品可靠性的瓶颈。许多开发者发现,手册标注的1万次擦写限制在实际应用中可能过于保守——通过合理的工程技巧,某…...
手把手教你搞定RK3588开发板ADB连接失败(从硬件到Android系统全排查)
手把手教你搞定RK3588开发板ADB连接失败(从硬件到Android系统全排查) 刚拿到RK3588开发板时,最令人兴奋的莫过于通过ADB连接开始调试。但当你插上USB线,却发现设备管理器里空空如也,那种挫败感简直让人抓狂。别担心&am…...
嵌入式实时调度算法选型指南(优先级抢占 vs 时间片轮转 vs EDF深度对比)
第一章:嵌入式实时调度算法选型导论嵌入式实时系统对任务响应的确定性与可预测性提出严苛要求,调度算法作为内核核心组件,直接决定系统能否满足截止期约束、资源利用率及可扩展性等关键指标。选型过程需综合考量任务模型(周期/非周…...
OpCore Simplify:黑苹果配置范式重构与自动化工程实践
OpCore Simplify:黑苹果配置范式重构与自动化工程实践 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify 在开源硬件兼容性领域,黑…...
基于Simulink的自适应反步法(Adaptive Backstepping)控制
目录 手把手教你学Simulink——基于Simulink的自适应反步法(Adaptive Backstepping)控制 摘要 一、背景与挑战 1.1 非线性系统控制的痛点 1.1.1 未知参数的影响 1.1.2 传统反步法的局限 1.2 自适应反步法的核心优势 1.2.1 原理:参数估计+反步设计融合…...
BGE-Large-Zh惊艳效果:‘感冒了怎么办’匹配健康科普文TOP3精准排序
BGE-Large-Zh惊艳效果:‘感冒了怎么办’匹配健康科普文TOP3精准排序 1. 项目简介 BGE-Large-Zh语义向量化工具是一款基于FlagEmbedding库和BAAI/bge-large-zh-v1.5模型开发的本地化语义处理工具。这个工具专门针对中文语境进行了深度优化,能够将文本转…...
