当前位置: 首页 > news >正文

【算法学习】-【双指针】-【复写零】

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用于控制放入操作是否需要停止。接着遍历原数组,遇到非零元素movsize一起++;遇到零元素mov++size+=2表示将0放了两次到新数组中;循环直至size大于等于原数组的大小。循环结束后mov的位置即为新数组的最后一个数(示例一中的4)在原数组中的位置的下一个位置,故让mov--指向新数组的最后一个数在原数组中的位置,准备进行复写

  • 接下来是复写过程
    原数组最后一个元素开始进行复写;用一个指针end指向它,接着以mov指针所对应的元素为判断依据,若是非零元素,则执行一次复写,复写完成后movend往前移一位;若是零元素,则执行两次复写,复写完成后mov往前移一位end往前移两位。循环执行如上过程直至复写完整个数组。

  • 还有个坑:
    上面说过,当新数组的大小等于或超过了原数组的大小时停止复写,等于原数组算是“正常”情况,新数组中零元素的个数为偶数个,即在原数组上复写时可以执行正确执行两次复写;但还有新数组的大小超过原数组的大小的情况,此时新数组中零元素的个数并不是偶数个,按照正常复写过程直接在原数组上复写会覆盖掉之前的数据,出现这种情况原因是最后需要复写两个零但空间只能再容纳一个零了,如这个测试用例:
    [8,4,5,0,0,0,0,7]
    i = 5时,新数组中的size = 7,此时仅能再放入一个0,这意味着用双指针进行复写的时候,最后一个0只能复写一次
    解决方法
    根据遇到0放入两次的操作,不符合条件跳出循环后,size的值是大于原数组的大小的(准确来说等于原数组大小+1),对这种情况进行特殊判断后先将最后一个元素进行复写,且movend都往前移一位后,再进行正常的复写即可。

完整的代码如下

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原题链接&#xff1a;1089. 复写零 下面是题目描述&#xff1a; 给你一个长度固定的整数数组 arr &#xff0c;请你将该数组中出现的每个零都复写一遍&#xff0c;并将其余的元素向右平移。 注意&#xff1a;请不要在超过该数组长度的位置写入元素。请对输入的数组 …...

【算法优选】双指针专题——叁

文章目录 &#x1f60e;前言&#x1f333;[两数之和](https://leetcode.cn/problems/he-wei-sde-liang-ge-shu-zi-lcof/)&#x1f6a9;题目描述&#xff1a;&#x1f6a9;算法思路&#xff1a;&#x1f6a9;算法流程&#xff1a;&#x1f6a9;代码实现 &#x1f384;[三数之和]…...

Java栈的压入、弹出序列(详解)

目录 1.题目描述 2.题解 方法1 方法2 1.题目描述 输入两个整数序列&#xff0c;第一个序列表示栈的压入顺序&#xff0c;请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序&#xff0c;序列4,5,3,2,1是该压栈序…...

RabbitMQ学习笔记(消息发布确认,死信队列,集群,交换机,持久化,生产者、消费者)

MQ&#xff08;message queue&#xff09;&#xff1a;本质上是个队列&#xff0c;遵循FIFO原则&#xff0c;队列中存放的是message&#xff0c;是一种跨进程的通信机制&#xff0c;用于上下游传递消息。MQ提供“逻辑解耦物理解耦”的消息通信服务。使用了MQ之后消息发送上游只…...

PyTorch - 模型训练损失 (Loss) NaN 问题的解决方案

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/133378367 在模型训练中&#xff0c;如果出现 NaN 的问题&#xff0c;严重影响 Loss 的反传过程&#xff0c;因此&#xff0c;需要加入一些微小值…...

8、Nacos服务注册服务端源码分析(七)

本文收录于专栏 Nacos 中 。 文章目录 前言确定前端路由CatalogController.listDetail()ServiceManager总结 前言 前文我们分析了Nacos中客户端注册时数据分发的设计链路&#xff0c;本文根据Nacos前端页面请求&#xff0c;看下前端页面中的服务列表的数据源于哪里。 确定前端…...

MySQL使用Xtrabackup在线做主从

1、主库上操作 1.1前提 172.16.11.2&#xff08;主库&#xff09; 172.16.11.4&#xff08;从库&#xff09; 在执行备份之前&#xff0c;确保数据库没有锁定&#xff0c;以避免备份期间的任何写操作。 确保主库上的 MySQL 服务器正在运行&#xff0c;以便备份数据的一致性。…...

scala基础入门

一、Scala安装 下载网址&#xff1a;Install | The Scala Programming Language ideal安装 &#xff08;1&#xff09;下载安装Scala plugins &#xff08;2&#xff09;统一JDK环境&#xff0c;统一为8 &#xff08;3&#xff09;加载Scala &#xff08;4&#xff09;创建工…...

【Java-LangChain:面向开发者的提示工程-5】推断

第五章 推断 推断任务可以看作是模型接收文本作为输入&#xff0c;并执行某种分析的过程。其中涉及提取标签、提取实体、理解文本情感等等。如果你想要从一段文本中提取正面或负面情感&#xff0c;在传统的机器学习工作流程中&#xff0c;需要收集标签数据集、训练模型、确定如…...

【C++】手撕vector(vector的模拟实现)

手撕vector目录&#xff1a; 一、基本实现思路方针 二、vector的构造函数剖析&#xff08;构造歧义拷贝构造&#xff09; 2.1构造函数使用的歧义问题 2.2 vector的拷贝构造和赋值重载&#xff08;赋值重载不是构造哦&#xff0c;为了方便写在一起&#xff09; 三、vector的…...

智能指针那些事

​《Effective Modern C》学习笔记之条款二十一&#xff1a;优先选用std::make_unique和std::make_shared,而非直接new - 知乎...

Fiddler抓取手机https包的步骤

做接口测试时&#xff0c;有时我们需要使用fiddler进行抓包分析&#xff0c;那么如何抓取https包。主要分为以下七步&#xff1a; 1.设置fiddler选项&#xff1a;Tools->Options,按如下图勾选 2.下载并安装Fiddler证书生成器 下载地址&#xff1a;http://www.telerik.com/…...

idea没有maven工具栏解决方法

背景&#xff1a;接手的一些旧项目&#xff0c;有pom文件&#xff0c;但是用idea打开的时候&#xff0c;没有认为是maven文件&#xff0c;所以没有maven工具栏&#xff0c;不能进行重新加载pom文件中的依赖。 解决方法&#xff1a;选中pom.xml文件&#xff0c;右键 选择添加为…...

levelDB引擎

一、背景 1.1、影响磁盘性能的因素&#xff1a; 主要受限于磁盘的寻道时间&#xff0c;优化磁盘数据访问的方法是尽量减少磁盘的IO次数。磁盘数据访问效率取决于磁盘IO次数&#xff0c;而磁盘IO次数又取决于数据在磁盘上的组织方式。磁盘数据存储大多采用B树类型数据结构&…...

IM同步服务

设计概述 后台同步方案的设计就是数据存储结构的设计&#xff0c;如何快速体现“信息变化”&#xff0c;如何快速计算出“变化信息”。后台数据存储结构是由同步协议中同步契约决定的。 设计方案 该方案的同步是按照业务粒度来划分&#xff0c;只需要同步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函数做就行。&#xff08;如果不存在那个子串就返回-1&#xff0c;否则返回第一次出现位置&#xff09; 注意题目中编号是从1开始的。 时间复杂度&#xff1a;O(log(n))。find函数有一定代价&#xff0c;我记…...

visual studio的安装及scanf报错的解决

visual studio是一款很不错的c语言编译器 下载地址&#xff1a;官网 点击后跳转到以下界面 下滑后点击下载Vasual Sutdio&#xff0c;选择社区版即可 选择位置存放下载文件后&#xff0c;即可开始安装 安装时会稍微等一小会儿。然后会弹出这个窗口&#xff0c;我们选择安装位…...

React生命周期

React的生命周期主要是指React组件从创建到销毁的过程&#xff0c;包括三个阶段&#xff1a;挂载期&#xff08;实例化期&#xff09;、更新期&#xff08;存在期&#xff09;、卸载期&#xff08;销毁期&#xff09; 挂载期&#xff1a; constructor&#xff08;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详细配置与…...

基于当前项目通过npm包形式暴露公共组件

1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹&#xff0c;并新增内容 3.创建package文件夹...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢

随着互联网技术的飞速发展&#xff0c;消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁&#xff0c;不仅优化了客户体验&#xff0c;还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用&#xff0c;并…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...

音视频——I2S 协议详解

I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议&#xff0c;专门用于在数字音频设备之间传输数字音频数据。它由飞利浦&#xff08;Philips&#xff09;公司开发&#xff0c;以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...

Go 并发编程基础:通道(Channel)的使用

在 Go 中&#xff0c;Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式&#xff0c;用于在多个 Goroutine 之间传递数据&#xff0c;从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...

LLMs 系列实操科普(1)

写在前面&#xff1a; 本期内容我们继续 Andrej Karpathy 的《How I use LLMs》讲座内容&#xff0c;原视频时长 ~130 分钟&#xff0c;以实操演示主流的一些 LLMs 的使用&#xff0c;由于涉及到实操&#xff0c;实际上并不适合以文字整理&#xff0c;但还是决定尽量整理一份笔…...

【JavaSE】多线程基础学习笔记

多线程基础 -线程相关概念 程序&#xff08;Program&#xff09; 是为完成特定任务、用某种语言编写的一组指令的集合简单的说:就是我们写的代码 进程 进程是指运行中的程序&#xff0c;比如我们使用QQ&#xff0c;就启动了一个进程&#xff0c;操作系统就会为该进程分配内存…...

STM32HAL库USART源代码解析及应用

STM32HAL库USART源代码解析 前言STM32CubeIDE配置串口USART和UART的选择使用模式参数设置GPIO配置DMA配置中断配置硬件流控制使能生成代码解析和使用方法串口初始化__UART_HandleTypeDef结构体浅析HAL库代码实际使用方法使用轮询方式发送使用轮询方式接收使用中断方式发送使用中…...

[ACTF2020 新生赛]Include 1(php://filter伪协议)

题目 做法 启动靶机&#xff0c;点进去 点进去 查看URL&#xff0c;有 ?fileflag.php说明存在文件包含&#xff0c;原理是php://filter 协议 当它与包含函数结合时&#xff0c;php://filter流会被当作php文件执行。 用php://filter加编码&#xff0c;能让PHP把文件内容…...

如何应对敏捷转型中的团队阻力

应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中&#xff0c;明确沟通敏捷转型目的尤为关键&#xff0c;团队成员只有清晰理解转型背后的原因和利益&#xff0c;才能降低对变化的…...