2024年10月25日练习(双指针算法)

一.283. 移动零 - 力扣(LeetCode)

     1.题目描述:

这里题目要求了说必须在不复制数组的情况下对数组进行原地操作,所以说不能来用暴力的解法来

实现。

2.算法原理:

    这个题目就是经典的数组划分,数组分块问题,就是将数组划成两个部分,拿这个题目来说,一

个划成非0元素部分,一个划分成0元素的部分。

这里虽然叫双指针算法,但是这里在数组里,所以我们用数组下标代表这“双指针”,而不是真的去

创建两个指针。

这里我们来演示一下这两个指针在走的过程中是怎么划分数组的:

这里两个指针将整个数组划分为三个区间,那么这两个指针代表的是什么呢?

首先cur指针代表的是从左往右扫描数组,也就是遍历数组的作用。

dest指针代表的是已处理区间,非零元素的最后一个位置。

因为这两个指针走的时候肯定是错开走的,所以会划分成三个不同的区间:

在处理过的区间题目的要求是,非0元素全部在右边,0元素全部在左边,然后dest这个指针的作用

就非常明显了,这个处理过的区间又细分为非0元素区间和0元素区间。

这就是划分出来的三个区间。

当cur指针走到最后时:

这时候你再看,待处理区间已经没有了,就剩下dest指针划分出来的两个区间了,也就是非0元素

区间和0元素的区间,这时也就完成了题目的要求,完成了数组的划分。

那么现在就拿一个例子来看看:

上面也已经说过了cur指针和dest的指针的作用是什么,这里dest指的是非0元素的最后一个位置,

所以有可能像上面这种情况首元素就是非0元素,所以dest所在的位置就是数组下标为-1的位置即

可。

那么遍历的过程是如何的呢?

这里就一直遵循这三个区间即可,一直保持着这三个区间走就行:

首先遇到0,cur++即可,dest不动。现在cur指针指向1:

因为遇到了非0元素,所以先让dest+1,然后再与cur去交换,完成后,cur再++,上面就是完成该

操作的情况,此时再看也是遵循那个三个区间的要求。

这里cur指针又指向了0,所以只有cur++即可:

这里cur又碰到了非0元素,所以先让dest+1,再与cur指针指向的值完成交换,完成交换cur再++:

然后cur又碰到了非0元素,所以继续上述步骤,dest+1,然后与cur交换,cur再++:

此时再看,cur也已经完成了遍历数组的任务,此时dest正好将数组划分为两个区间,左边非0元素

区间,右边0元素的区间。

这就是这个题目的整个算法原理。

3.代码实现:

class Solution {
public:void moveZeroes(vector<int>& nums) {int cur=0;int dest=-1;for(cur=0;cur<nums.size();cur++){if(nums[cur]!=0){//处理非0元素swap(nums[++dest],nums[cur]);}}}
};

这就是利用双指针算法解决这个问题的所有思路。

二.1089. 复写零 - 力扣(LeetCode)

   1.题目描述:

这道题也是原地操作,并且不能越界

2.算法原理:

   这里的解法还是双指针算法,这里题目让我们的是就地操作,而双指针算法的情况下我们先“异

地”操作,然后优化成双指针下的“就地”操作,这里随便拿一个题目中的例子来分析一下:

这里cur就指向原数组来遍历一下,然后dest指向另一数组,如果cur遇到的是非0元素,就复制到

dest指向的位置,如果cur遇到的是0元素,就复写两次到dest的数组中。

第一次cur指向的元素是1,所以dest直接复制下来,然后cur,dest都加加,现在,cur指向的元素

是0,所以dest复写两次:

复写完成后cur++,dest++,然后再次去判断cur指向的是非0元素,先复制,再cur++,dest++:

然后继续上述操作:

此时cur又遇到了0元素,dest继续复写,复写完成后,dest++,cur++:

此时又是非0元素,直接复制,然后cur++,dest++:

此时dest越界,此时也完成了,题目要求的复写任务。

这是异地操作,那我们能否改为就地操作:

这里我们直接将cur,dest指向同一数组,然后来操作一下我们上面写的复写过程:

此时遇到的是非0元素,所以直接让cur++,dest++:

此时cur遇到了0元素,此时就要复写了,那么dest+1,然后复写0:

此时已经出错了,因为原来位置的值是2,而这里已经被覆盖了,所以这个肯定不对了。

而我们这里既然从前往后会导致数据覆盖,那么我们就换一种思路,我们就从后向前走,看看能不

能解决覆盖问题:

这里dest指向数组最后一个元素的位置,然后cur指向最后一个复写的数,上面的操作我们知道

了,最后一个复写的数是4,所以这里我们直接指向4,如果cur和dest指向同一位置,是肯定不行

的,然后此时来从后向前来完成复写操作:

此时cur指向的是4,那么直接复制给dest指向的位置,然后cur--,dest--:

此时遇到0,那么dest直接往前复写两个0,然后dest--,cur--:

此时cur遇到非0元素,那么直接复制给dest,然后dest--,cur--:

此时cur又遇到非0元素,继续复制给dest,然后dest--,cur--:

我们之所以可以直接修改,因为我们发现这里3已经被复写过了,就不会发生覆盖了,所以可以直

接复写就行了。

这里cur遇到了0元素,那么dest复写两次,然后cur--,dest--:

,这是cur遇到了非零元素,直接复制就好了,然后dest--,cur--:

此时这时就完成了复写操作,比较一下,复写的没毛病,所以双指针从后向前走就可以完成这个操

作。

总结一下:1.首先cur指向的是最后一个复写的数,因为上面我们可以很直观的看到最后一个复写

的数,所以我们在这里首先要找到最后一个需要复写的数

                  2.我们要从后向前完成复写操作

那么第一步我们怎么找到最后一个复写的数呢?

         其实还是一个双指针算法,定义一个cur指针指向数组头元素,然后dest指针指向-1的位置:

cur的作用还是遍历数组,而dest的定义是最后一个需要复写的位置,因为一开始我们并不知道,

最后一个需要复写的位置在哪里,所以我们先定义到-1这个位置。

首先先判断cur指向的元素是否为非0元素,如果不是dest走一步,然后再判断dest是否走到了最

后。如果是非0元素,dest就走两步,因为要复写0,然后再判断dest'是否走到了最后。这就是

判断的顺序。

现在cur位置的值是非零元素,所以dest向后走一步,dest并没有到结束位置,然后cur++:

此时cur指向的是0元素,所以dest向后移动两步,dest并没有结束,所以cur++:

此时cur指向非0元素的值,所以dest向后移动一步,dest并没有结束,所以cur++:

跟上面遇到2的情况一样,继续:

此时cur遇到了0,那么dest就走两步,此时dest还没有到结束的位置,所以cur++:

此时cur指向的是非零元素,所以dest向后移动一步,移动一步之后,我们发现已经到了数组的末

尾所以终止接下来的操作,所以cur不加加:

此时我们发现cur正好是指向我们最后一个复写的数,而且此时dest正好是我们要从后向前完成复

写操作的位置,所以后续可以直接开始就行了。

但是还有特殊情况:

就是这个例子,当我们去找最后一个复写的数时,就是按照上面的思路去走,这里就不详细写了,

直接快进到最后的位置:

此时我们发现,dest直接越界了,如果我们此时按照这个位置直接去完成从前向后复写的操作,编

译器是会直接报错的:

所以我们要处理一下边界情况,这里dest出边界一定是复写的最后一个数是0导致的,所以我们要

单独处理一下这种情况:

因为最后一个复写的数是0,所以我们直接将n-1的位置改为0,然后让dest向前移动两步,dest向

前移动一步,此时再从后向前完成复写就不会出错了:

这就是处理后的位置。

总结一下整个算法原理我们在做什么:

3.代码实现:

class Solution {
public:void duplicateZeros(vector<int>& arr) {int cur=0;int dest=-1;//先找到最后一个复写的数int num=arr.size();while(cur<num){if(arr[cur]!=0){dest++;}else{dest+=2;}if(dest>=num-1){break;}cur++;}//处理边界情况if(dest==num){arr[num-1]=0;dest-=2;cur--;}//从后向前完成复写操作:while(cur>=0){if(arr[cur]!=0){arr[dest--]=arr[cur--];}else{arr[dest--]=0;arr[dest--]=0;cur--;}}}
};

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

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

相关文章

react-signature-canvas 实现画笔与橡皮擦功能

react-signature-canvas git 地址 代码示例 import React, { Component } from react import { createRoot } from react-dom/clientimport SignaturePad from ../../src/index.tsximport * as styles from ./styles.module.cssclass App extends Component {state { trimmed…

NLTK无法下载?

以下内容仅为当前认识&#xff0c;可能有不足之处&#xff0c;欢迎讨论&#xff01; 文章目录 nltk无法下载怎么办&#xff1f;什么是NLTK&#xff1f;为什么要用NLTK&#xff1f;如何下载&#xff1f; nltk无法下载怎么办&#xff1f; 什么是NLTK&#xff1f; NLTK是学习自然…

【Qt】窗口——Qt窗口的概念、常用的窗口函数、菜单栏、工具栏、状态栏、浮动窗口、对话框

文章目录 Qt窗口Qt窗口的概念菜单栏工具栏状态栏浮动窗口对话框 Qt 窗口 Qt窗口的概念 QMainWindow 类概述&#xff1a; QMainWindow 是一个为用户提供主窗口程序的类&#xff0c;它继承自 QWidget 类&#xff0c;并且提供了一个预定义的布局。 菜单栏 菜单栏常用属性&#xf…

紫光同创——盘古 50KN 网口板

本原创文章由深圳市小眼睛科技有限公司创作&#xff0c;版权归本公司所有&#xff0c;如需转载&#xff0c;需授权并注明出处&#xff08;www.meyesemi.com) 一、开发系统介绍 盘古 50KN 网口板开发板&#xff08;MES50H-Ethernet&#xff09;采用了核心板扩展板的结 构&#…

---synchronized 关键字---

在多线程编程中&#xff0c;由于代码的并发执行&#xff0c;导致了不同的线程在修改相同的变量会导致变量的值错误 比如 变量 c 2&#xff0c;这里有线程A 和 B一起使用 c变量并对他加1&#xff0c;这时就会有多中情况 这里要注意的是变量c是储存在内存中的&#xff0c;而线…

【git】 git 删除了文件,如何找回

git 删除了文件&#xff0c;如何找回 使用 git revert 并不是恢复误删除文件的最佳方法&#xff0c;因为 git revert 通常用于撤销已经提交的更改&#xff08;生成一个反向提交&#xff09;。如果你误删除了文件&#xff0c;还未提交更改&#xff0c;或者已经提交但想恢复删除…

2024年9月电子学会青少年软件编程Python等级考试(三级)真题试卷

2024年9月青少年软件编程Python等级考试&#xff08;三级&#xff09;真题试卷 选择题 第 1 题 单选题 以下python表达式的值为True的是&#xff1f;&#xff08; &#xff09; A.all( ,1,2,3) B.any([]) C.bool(abc) D.divmod(6,0) 第 2 题 单选题 下列python代码的…

钉钉与金蝶云星空数据集成:提高企业付款申请单处理效率

钉钉数据集成到金蝶云星空&#xff1a;付款申请单的自动下推生成 在企业日常运营中&#xff0c;如何高效地管理和处理付款申请单是一个关键问题。为了提升这一流程的效率&#xff0c;我们采用了轻易云数据集成平台&#xff0c;将钉钉中的付款申请单数据无缝对接到金蝶云星空系…

Spring Boot助力的厨艺互动平台开发指南

2 相关技术 2.1 Spring Boot框架简介 Spring Boot是由Pivotal团队提供的全新框架&#xff0c;其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置&#xff0c;从而使开发人员不再需要定义样板化的配置。通过这种方式&#xff0c;Sprin…

代码学习:如何阅读开源代码

如何阅读开源代码 准备 目的&#xff1a;学习代码&#xff0c;代码添加新功能、旧代码重构知识准备&#xff1a;技术基础、编程基础、文档开发环境&#xff1a;依赖环境及操作系统笔记&#xff1a;添加代码注释及重要思路记录文档 实操 阅读项目Readme.md&#xff1a;大致了…

基于边缘计算的智能门禁系统架构设计分析

案例 阅读以下关于 Web 系统架构设计的叙述&#xff0c;回答问题1至问题3。 【说明】 某公司拟开发一套基于边缘计算的智能门禁系统&#xff0c;用于如园区、新零售、工业现场等存在来访被访业务的场景。来访者在来访前&#xff0c;可以通过线上提前预约的方式将自己的个人信息…

软考:CORBA架构

CORBA过时了吗 CORBA指南 个人小结&#xff1a; IPC&#xff0c;进程间通信&#xff0c;Socket应用在不同机器之间的通信 RPC是一种技术思想而非一种规范 但站在八九十年代的当口&#xff0c;简单来说&#xff0c;就是我在本地调用了一个函数&#xff0c;或者对象的方法&…

沧穹科技室内音频“北斗”定位技术亮相第三届北斗规模应用国际峰会

10月24日-28日&#xff0c;由国家发展改革委、国家网信办、交通运输部、湖南省人民政府共同主办的第三届北斗规模应用国际峰会于株洲国际会展中心隆重开幕。沧穹科技总经理戴坚先生受邀出席开幕式&#xff0c;公司自研室内音频“北斗”定位产品亮相北斗规模应用示范场景区。 峰…

NSSCTF刷题篇web部分

源码泄露 [FSCTF 2023]寻找蛛丝马迹 这个源码泄露&#xff0c;可以记录一下&#xff0c;涉及的知识点比较多 打开环境 查看源码&#xff0c; 第一段flag 乱码&#xff0c;恢复一下 乱码恢复网站&#xff1a;乱码恢复 (mytju.com) 剩下的就只说方法 http://node4.anna.nss…

Pytest-Bdd-Playwright 系列教程(2):支持在多浏览器、多环境中执行测试

Pytest-Bdd-Playwright 系列教程&#xff08;2&#xff09;&#xff1a;支持在多浏览器、多环境中执行测试 前言一、 修改 conftest.py 文件二、创建配置文件三、修改search_steps.py文件四、运行测试总结 前言 本文教程知识点&#xff1a; 支持在多浏览器、多环境中执行测试 …

【ROS概述】C++运行hello world

Python和C通用步骤&#xff1a; 一、创建工作空间并初始化 1、新建工作空间&#xff08;work space&#xff09;——使用终端&#xff08;ctrlaltT&#xff09; mkdir -p 空间名称/src 2、进入工作空间 cd 空间名称 可以在文件里看到同步变化&#xff0c;并且demo01_ws文…

SpringBoot项目上高并发问题的解决方案

案例&#xff1a;多个用户同时购买数量为1的商品&#xff0c;所以只能有一个购买成功 不加锁 会重复购买 乐观锁&#xff0c;加字段处理&#xff0c;在并发少的时候可以使用 加版本号字段&#xff0c;第一次查询数量的时候读取到版本号&#xff0c;更新数量时用同样的版本号更新…

前端经典【面试题】持续更新HTML、CSS、JS、VUE、FLUTTER、性能优化等

HTML/CSS 面试题 什么是语义化 HTML&#xff1f; 说明&#xff1a;语义化 HTML 使用 HTML 标签来描述内容的含义&#xff0c;而不仅仅是其外观。使用语义化标签可以提高可读性和可访问性&#xff0c;并对 SEO 友好。示例&#xff1a; <header><h1>网站标题</h1&…

服务器数据恢复—异常断电导致服务器挂载分区无法访问的数据恢复案例

服务器数据恢复环境&#xff1a; 某品牌服务器同品牌存储&#xff0c;Linux centos7EXT4文件系统。 服务器故障&#xff1a; 意外断电导致服务器操作系统不能正常启动。经过修复后系统可以正常启动&#xff0c;但是挂载的分区无法正常访问。使用fsck修复这个问题分区&#xff…

gin入门教程(7): 使用 Logrus + Lumberjack 创建日志中间件

结合 Logrus 和 Lumberjack&#xff0c;可以创建一个高效的日志中间件&#xff0c;用于记录请求和响应。以下是实现步骤&#xff1a; 1. 安装依赖 首先&#xff0c;确保安装了 Logrus 和 Lumberjack&#xff1a; go get github.com/sirupsen/logrus go get gopkg.in/natefin…