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

【算法专题--双指针算法】leetcode--283. 移动零、leetcode--1089. 复写零


🍁你好,我是 RO-BERRY
📗 致力于C、C++、数据结构、TCP/IP、数据库等等一系列知识
🎄感谢你的陪伴与支持 ,故事既有了开头,就要画上一个完美的句号,让我们一起加油

请添加图片描述


目录

  • 前言
  • 1. 移动零(easy)
  • 2. 解法(快排的思想:数组划分区间 - 数组分两块)
  • 3. 复写零(easy)
  • 4.解法(原地复写 - 双指针)


前言

双指针
常见的双指针有两种形式,一种是对撞指针,⼀种是左右指针。
对撞指针:一般用于顺序结构中,也称左右指针。

  • 对撞指针从两端向中间移动。一个指针从最左端开始,另⼀个从最右端开始,然后逐渐往中间逼
    近。
  • 对撞指针的终止条件一般是两个指针相遇或者错开(也可能在循环内部找到结果直接跳出循
    环),也就是:
    • left == right (两个指针指向同一个位置)
    • left > right (两个指针错开)

快慢指针:又称为龟兔赛跑算法,其基本思想就是使用两个移动速度不同的指针在数组或链表等序列
结构上移动。
这种方法对于处理环形链表或数组非常有用。
其实不单单是环形链表或者是数组,如果我们要研究的问题出现循环往复的情况时,均可考虑使用快
慢指针的思想。

快慢指针的实现方式有很多种,最常用的⼀种就是:

  • 在一次循环中,每次让慢的指针向后移动一位,而快的指针往后移动两位,实现一快一慢。

1. 移动零(easy)

「数组分两块」是非常常见的一种题型,主要就是根据一种划分方式,将数组的内容分成左右两部
分。这种类型的题,⼀般就是使用「双指针」来解决。

题目链接: 283. 移动零

题目描述:
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例 1:

输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]

示例 2:

输入: nums = [0]
输出: [0]

提示:

1 <= nums.length <= 104
-231 <= nums[i] <= 231 - 1
进阶:你能尽量减少完成的操作次数吗?


2. 解法(快排的思想:数组划分区间 - 数组分两块)

算法思路:

在本题中,我们可以用一个 cur 指针来扫描整个数组,另一个 dest 指针用来记录非零数序列的最后一个位置。根据 cur 在扫描的过程中,遇到的不同情况,分类处理,实现数组的划分。
在 cur 遍历期间,使 [0, dest] 的元素全部都是非零元素, [dest + 1, cur - 1] 的元素全是零。

算法流程:

  1. 初始化 cur = 0 (用来遍历数组), dest = -1 (指向非零元素序列的最后⼀个位置。
    因为刚开始我们不知道最后⼀个非零元素在什么位置,因此初始化为 -1 )
  2. cur 依次往后遍历每个元素,遍历到的元素会有下面两种情况:

i. 遇到的元素是 0 , cur 直接 ++ 。因为我们的⽬标是让 [dest + 1, cur - 1] 内的元素全都是零,因此当 cur 遇到 0 的时候,直接 ++ ,就可以让 0 在 cur - 1的位置上,从而在 [dest + 1, cur - 1] 内;

ii. 遇到的元素不是 0 , dest++ ,并且交换 cur 位置和 dest 位置的元素,之后让cur++ ,扫描下⼀个元素。

  • 因为 dest 指向的位置是非零元素区间的最后⼀个位置,如果扫描到⼀个新的非零元素,那么它的位置应该在 dest + 1 的位置上,因此 dest 先自增 1 ;
  • dest++ 之后,指向的元素就是 0 元素(因为非零元素区间末尾的后⼀个元素就是0 ),因此可以交换到 cur 所处的位置上,实现 [0, dest] 的元素全部都是非零元素, [dest + 1, cur - 1] 的元素全是零。

在这里插入图片描述

C++ 算法代码:

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

C++ 代码结果:
在这里插入图片描述

Java 算法代码:

class Solution
{public void moveZeroes(int[] nums){for (int cur = 0, dest = -1; cur < nums.length; cur++)if (nums[cur] != 0) // 仅需处理⾮零元素{dest++; // dest 先向后移动⼀位// 交换int tmp = nums[cur];nums[cur] = nums[dest];nums[dest] = tmp;}}
}

3. 复写零(easy)

题目链接: 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 <= arr.length <= 104
0 <= arr[i] <= 9

4.解法(原地复写 - 双指针)

确定目标位置:

  1. 首先,使用两个指针 dest 和 cur 来确定每个位置复制0后应该放置的位置。cur 指针用于遍历原始数组,而 dest 指针则用于确定在复制0后应该放置新元素的位置。cur 最终的位置就是复写后数组的最后一个数的位置。

如果 arr[cur] 不为0,那么 dest 只增加1,因为当前元素不需要复制。
如果 arr[cur] 为0,那么 dest 增加2,因为需要复制一个0放在当前0的后面。
处理边界情况:在遍历过程中,如果 dest 超过了数组的最大索引 n-1,则说明没有足够的空间来放置所有的0。在这种情况下,将数组的最后一个元素设置为0,并将 dest 和 cur 指针相应地向后移动。

  1. 从后向前复写:在确定了所有元素的目标位置后,从数组的末尾开始,根据原始数组中的元素值,将元素复制到它们的目标位置。

如果 arr[cur] 不为0,则将其复制到 arr[dest],并将两个指针都向前移动1位。
如果 arr[cur] 为0,则先复制一个0到 arr[dest],再复制另一个0到 arr[dest-1],然后将 cur 向前移动1位,dest 向前移动2位。

在这里插入图片描述

解题方法

该算法使用双指针技术,通过一次遍历来确定每个元素的目标位置,然后从后向前进行复写。这种方法避免了额外的空间开销,并且只进行了一次遍历,因此效率较高。

时间复杂度: O(n),其中n是数组的长度。算法只进行了一次遍历,因此时间复杂度是线性的。
空间复杂度: O(1),算法只使用了常数个额外变量,没有使用与数组大小相关的额外空间。

总结

这个算法是一种高效的原地修改算法,它利用了双指针技术来避免额外的空间开销,并且只进行了一次遍历。这种算法的时间复杂度和空间复杂度都是最优的。

C++ 算法代码:

class Solution {
public:void duplicateZeros(vector<int>& arr) {//找最后一个数 int dest=-1,cur=0,n=arr.size();while(cur<n){if(arr[cur])dest++;elsedest+=2;if(dest>=n-1)break;cur++;}//边界情况if(dest>=n){arr[n-1]=0;dest-=2;cur--;}while(cur>=0){if(arr[cur])arr[dest--]=arr[cur--];else{arr[dest--]=arr[cur];arr[dest--]=arr[cur--];}}}
};

在这里插入图片描述
Java 算法代码:

class Solution
{public void duplicateZeros(int[] arr){int cur = 0, dest = -1, n = arr.length;// 1. 先找到最后⼀个需要复写的数while (cur < n){if (arr[cur] == 0) dest += 2;else dest += 1;if (dest >= n - 1) break;cur++;}// 2. 处理⼀下边界情况if (dest == n){arr[n - 1] = 0;cur--; dest -= 2;}// 3. 从后向前完成复写操作while (cur >= 0){if (arr[cur] != 0) arr[dest--] = arr[cur--];else{arr[dest--] = 0;arr[dest--] = 0;cur--;}}}
}

相关文章:

【算法专题--双指针算法】leetcode--283. 移动零、leetcode--1089. 复写零

&#x1f341;你好&#xff0c;我是 RO-BERRY &#x1f4d7; 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 &#x1f384;感谢你的陪伴与支持 &#xff0c;故事既有了开头&#xff0c;就要画上一个完美的句号&#xff0c;让我们一起加油 目录 前言1. 移动零&#xff0…...

【JavaEE -- 多线程3 - 多线程案例】

多线程案例 1.单例模式1.1 饿汉模式的实现方法1.2 懒汉模式的实现方法 2. 阻塞队列2.1 引入生产消费者模型的意义&#xff1a;2.2 阻塞队列put方法和take方法2.3 实现阻塞队列--重点 3.定时器3.1 定时器的使用3.2 实现定时器 4 线程池4.1 线程池的使用4.2 实现一个简单的线程池…...

k8s的pod服务升级,通过部署helm升级

要通过Helm升级Kubernetes&#xff08;k8s&#xff09;中的Pod服务&#xff0c;你可以按照以下步骤进行操作&#xff1a; 安装Helm&#xff1a; 如果你还没有安装Helm&#xff0c;可以通过官方文档提供的方式进行安装。添加Helm仓库&#xff1a; 确保你已经添加了包含你要升级…...

复现文件上传漏洞

一、搭建upload-labs环境 将下载好的upload-labs的压缩包&#xff0c;将此压缩包解压到WWW中&#xff0c;并将名称修改为upload&#xff0c;同时也要在upload文件中建立一个upload的文件。 然后在浏览器网址栏输入&#xff1a;127.0.0.1/upload进入靶场。 第一关 选择上传文件…...

Java 内存异常

内存溢出 内存溢出指的是在程序执行过程中&#xff0c;申请的内存超过了系统实际可用的内存资源。 内存溢出的常见情况&#xff1a; 创建大量对象并持有引用&#xff1a;在程序中创建大量对象并持有对这些对象的引用&#xff0c;而没有及时释放这些引用&#xff0c;导致堆内存…...

Windows11去掉 右键菜单的 AMD Software:Adrenalin Edition 选项

Windows11去掉 右键菜单的 AMD Software:Adrenalin Edition 选项 运行regedit打开注册表编辑器 先定位到 计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Classes\PackagedCom\Package 计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Classes\PackagedCom\Package找到 AdvancedMicroDevicesInc-2.…...

uniapp实现我的订单页面无感 - 删除数据

在进入我们的订单页面时进行获取列表&#xff0c;上拉加载&#xff0c;下拉刷新等请求&#xff0c;我们在删除数据时&#xff0c;请求删除接口后&#xff0c;不要重新去请求数据&#xff0c;不要重新去请求数据&#xff0c;不要重新去请求数据 重新请求会刷新页面中的数据 方…...

MySQL—redo log、undo log以及MVCC

MySQL—redo log、undo log以及MVCC 首先回忆一下MySQL事务的四大特性&#xff1a;ACID&#xff0c;即原子性、一致性、隔离性和持久性。其中原子性、一致性、持久性实际上是由InnoDB中的两份日志保证的&#xff0c;一份是redo log日志&#xff0c;一份是undo log日志&#xff…...

13 list的实现

注意 实现仿cplus官网的list类&#xff0c;对部分主要功能实现 实现 文件 #pragma once #include <assert.h>namespace mylist {template <typename T>struct __list_node{__list_node(const T& x T()): _prev(nullptr), _next(nullptr), _data(x){}__lis…...

如何用client-go获取k8s因硬盘容量、cpu、内存、gpu资源不够引起的错误信息?

在Kubernetes中&#xff0c;你可以使用client-go库来获取Pod的状态和事件&#xff0c;这些信息可能包含了由于资源不足引起的错误信息。 以下是一个基本的示例&#xff0c;展示如何使用client-go来获取Pod的状态和事件&#xff1a; package mainimport ("flag"&quo…...

IDEA编译安卓源码TVBox(2)

一、项目结构&#xff1a;主要app和player app结构 二、增加遥控器按键选台 修改LivePlayActivity.java 1、声明变量 public String channelId "";public Timer timer new Timer();public Toast mToast;2、定义方法 private void mToastShow(String s){mToast …...

【C#】.net core 6.0 使用第三方日志插件Log4net,配置文件详细说明

欢迎来到《小5讲堂》 大家好&#xff0c;我是全栈小5。 这是《C#》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解&#xff0c; 特别是针对知识点的概念进行叙说&#xff0c;大部分文章将会对这些概念进行实际例子验证&#xff0c;以此达到加深对知识点的理解和掌握。…...

第十四届蓝桥杯省赛真题 Java 研究生 组【原卷】

文章目录 发现宝藏【考生须知】试题 A: 特殊日期试题 B: 与或异或试题 C: 棋盘试题 D: 子矩阵试题 E : \mathrm{E}: E: 互质数的个数试题 F: 小蓝的旅行计划试题 G: 奇怪的数试题 H: 太阳试题 I: 高塔试题 J \mathrm{J} J : 反异或 01 串 发现宝藏 前些天发现了一个巨牛的人…...

adb shell input text 输入中文

由于adb 不支持中文输入&#xff08;不支持 Unicode&#xff09;&#xff0c;需要使用虚拟键盘绕一圈。 可以直接参考和使用&#xff1a; https://github.com/senzhk/ADBKeyBoard # 通用方式 adb shell am broadcast -a ADB_INPUT_TEXT --es msg 赞 # mac/linux 支持 base64…...

Rudolf and the Ball Game

传送门 题意 思路 暴力枚举每一个妆台的转换条件 code #include<iostream> #include<cstdio> #include<stack> #include<vector> #include<algorithm> #include<cmath> #include<queue> #include<cstring> #include<ma…...

计算机毕业设计-基于大数据技术下的高校舆情监测与分析

收藏和点赞&#xff0c;您的关注是我创作的动力 文章目录 概要 一、研究背景与意义1.1背景与意义1.2 研究内容 二、舆情监测与分析的关键技术2.1 robot协议对本设计的影响2.2 爬虫2.2.1 工作原理2.2.2 工作流程2.2.3 抓取策略2.3 scrapy架构2.3.1 scrapy&#xff1a;开源爬虫架…...

WPF使用LiveCharts画图时,横坐标转换成时间

一、背景 使用LiveCharts画图时&#xff0c;横坐标通常为数值类型&#xff0c;要转换成时间等自定义类型&#xff0c;需要用到Formatter进行类型转换。 示例使用MVVM模式编写 二、View代码 关键是设置LabelFormatter属性 <lvc:CartesianChart Series"{Binding Series…...

Qt客户端开发的技术难点

在Qt客户端开发中&#xff0c;可能会遇到一些技术难点&#xff0c;这些难点可能与UI设计、性能优化、跨平台兼容性等方面有关。以下是一些可能的技术难点&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作…...

杰理AD155儿童玩具语音集成电路

一、杰理AD155集成电路是由杰理科技设计、开发和销售的一款产品&#xff0c;AD15系列 SoC 芯片支持以下特性&#xff1a; 工作电压&#xff1a;2.0V-5.5V主频可达120MHz的32bitCPU,片上集成20K字节SRAM&#xff0c;8K字节ICache支持最多2路解码同时运行&#xff0c;支持F1A/A/…...

git bash 命令行反应慢、卡顿(定位出根本原因)

参考该博主&#xff1a; https://blog.csdn.net/weixin_50212044/article/details/131575987?utm_mediumdistribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-0-131575987-blog-130024908.235v43pc_blog_bottom_relevance_base4&spm1001.210…...

springboot 百货中心供应链管理系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;百货中心供应链管理系统被用户普遍使用&#xff0c;为方…...

(十)学生端搭建

本次旨在将之前的已完成的部分功能进行拼装到学生端&#xff0c;同时完善学生端的构建。本次工作主要包括&#xff1a; 1.学生端整体界面布局 2.模拟考场与部分个人画像流程的串联 3.整体学生端逻辑 一、学生端 在主界面可以选择自己的用户角色 选择学生则进入学生登录界面…...

shell脚本--常见案例

1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件&#xff1a; 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...

线程同步:确保多线程程序的安全与高效!

全文目录&#xff1a; 开篇语前序前言第一部分&#xff1a;线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分&#xff1a;synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分&#xff…...

如何将联系人从 iPhone 转移到 Android

从 iPhone 换到 Android 手机时&#xff0c;你可能需要保留重要的数据&#xff0c;例如通讯录。好在&#xff0c;将通讯录从 iPhone 转移到 Android 手机非常简单&#xff0c;你可以从本文中学习 6 种可靠的方法&#xff0c;确保随时保持连接&#xff0c;不错过任何信息。 第 1…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

QT3D学习笔记——圆台、圆锥

类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体&#xff08;对象或容器&#xff09;QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质&#xff08;定义颜色、反光等&#xff09;QFirstPersonC…...

【Android】Android 开发 ADB 常用指令

查看当前连接的设备 adb devices 连接设备 adb connect 设备IP 断开已连接的设备 adb disconnect 设备IP 安装应用 adb install 安装包的路径 卸载应用 adb uninstall 应用包名 查看已安装的应用包名 adb shell pm list packages 查看已安装的第三方应用包名 adb shell pm list…...

从 GreenPlum 到镜舟数据库:杭银消费金融湖仓一体转型实践

作者&#xff1a;吴岐诗&#xff0c;杭银消费金融大数据应用开发工程师 本文整理自杭银消费金融大数据应用开发工程师在StarRocks Summit Asia 2024的分享 引言&#xff1a;融合数据湖与数仓的创新之路 在数字金融时代&#xff0c;数据已成为金融机构的核心竞争力。杭银消费金…...

C语言中提供的第三方库之哈希表实现

一. 简介 前面一篇文章简单学习了C语言中第三方库&#xff08;uthash库&#xff09;提供对哈希表的操作&#xff0c;文章如下&#xff1a; C语言中提供的第三方库uthash常用接口-CSDN博客 本文简单学习一下第三方库 uthash库对哈希表的操作。 二. uthash库哈希表操作示例 u…...