算法通过村第三关-数组白银笔记|数组双指针

文章目录

  • 前言
  • 什么是数组双指针
  • 数组中删除元素专题
    • 原地移除所有等值val的元素
      • 快慢双指针
      • 对撞双指针
      • 对撞+覆盖
    • 删除有序数组中的重复项
  • 总结


前言


提示:世间从不缺少辉煌的花冠,缺少的是被花冠渲染的淡定。

什么是数组双指针

这是一种长期总结下来的思想,可以说现在我们是站在巨人的肩膀上创作。

简单来说,数组里面的双指针,并不真的是指针,这里也没有指针的概念。双指针的思想好用,也存在特定的场景,比如数组,字符串等问题上面。我们举个例子说明吧。
26. 删除有序数组中的重复项 - 力扣(LeetCode)
在这里插入图片描述
在这里插入图片描述
就拿这个题目来说吧,数组最简单的的想法是,找到一个重复的数组,整体向前移动,看示例1:[1, 1,2], 找到第二个 1 后面的元素整体就向前移动(覆盖),当然这样的效率太低了。对示例2来说需要前后移动好几次才可以,不推荐使用☠。我们采用双指针的想法就不一样了,我们画个图简单说明一下:
在这里插入图片描述
思路:

  1. 定义两个指针slow,fast。slow便是当前位置之前的元素都不是重复的,而fast则一直向后找,知道找到和slow位置不一样的
  2. 找到不一样的后,slow向后移动一步,将arr[fast]的值复制给arr[slow],之后fast再继续向后循州,知道循环结束。
  3. 循环结束后slow以及之前的元素就是单一的了。
    当然这种是比较典型在双指针中的快慢指针了,除此之外还有其他的变题,对撞指针、背向指针等;

可以简单的这样去记双指针的三种经典模式:

  • 两个指针一起向前走(相亲相爱一起走)
  • 两头向中间走(冲破千难万险来爱你)
  • 中间向两头走(缘分已尽,就此拜拜)

数组中删除元素专题

所谓算法,其实将一个问题改改条件多折腾,要掌握核心点

原地移除所有等值val的元素

27. 移除元素 - 力扣(LeetCode)
在这里插入图片描述
在这里插入图片描述
在删除的时候,从删除位置的所有元素都需要向前移动,所以这提的关键是如果有很多的val的元素的是侯需要如何避免反复的向前移动呢

这个题就可以采用双指针的思想,以下是三种方法,可以了解一下

快慢双指针

整体思路和上面所画的图是一样的,定义两个指针slow和fast,初始值都是0。

slow之前的位置都是有效的部分,fast表示当前要访问的元素。

这样遍历的时候,fast不断的向后移动:

  • 如果nums[fast]的值不是val,就继续向前移动到nums[slow++]处
  • 如果nums[fast]的值为val,则fast继续向前移动,slow先等待。

画图展示:

在这里插入图片描述
这样表示的话,前面一部分是有效的,后面一部分是无效的

代码如下展示❤:

 /*** 方法1:使用快慢型双指针** @param nums* @param val* @return*/public static int removeElement(int[] nums, int val) {// 定义快慢指针int slow = 0;for (int fast = 0; fast < nums.length; fast++) {if (nums[fast] != val) {nums[slow] = nums[fast];slow++;}}//最后剩余元素的数量return slow;}

对撞双指针

对撞双指针,有的地方说是交换移除,核心思想是从右边找到不是val的值顶替左边的val的值。

我们看下图详解:
在这里插入图片描述
上图就是整体的思路,当left == right 的时候,left 以及左边的就是所有元素了

代码展示:

   /*** 方法2:使用对撞型双指针** @param nums* @param val* @return*/public static int removeElement2(int[] nums, int val) {// 定义左右指针int left = 0;int right = nums.length - 1;// left > right 退出循环while (left <= right) {  // 可以替换成  for(left = 0;left <= right // 满足条件就就换数据   该条件要放在前面if (nums[left] == val && nums[right] != val) {int temp = nums[left];nums[left] = nums[right];nums[right] = temp;} // 左边放有效数据if (nums[left] != val) {left++;}// 右边放无效数据if (nums[right] == val) {right--;}}return left;

当然这就是比较中规中矩的对撞双指针模式。这里注意顺序,条件顺序问题。

对撞+覆盖

结合上面的两种方法:当nums[left] == val 的时候,我们就直接将 nums[right]的位置上的元素直接覆盖nums[left],然后继续循环,否则才让left++当然这也属于双指针的思想,我们先画画图更好理解:
在这里插入图片描述
这时候写代码是不是很简单🥰

  /*** 方法三:优化对撞型双指针** @param nums* @param val* @return*/public static int removeElement3(int[] nums, int val) {// 定义左右指针int left = 0;int right = nums.length - 1;while (left <= right) {if (nums[left] == val) {nums[left] = nums[right];right--;} else {left++;}}return right + 1;}

对撞型双指针的过程与后面要学习的快速排序是一个思路,快速排序要比较多轮,而这里只执行了一轮。理解这里对于理解快速排序很重要。

注意:我们可以发现快慢型双指针留下的元素顺序与原始序列中的一直,当然对撞型就不一样了。

删除有序数组中的重复项

26. 删除有序数组中的重复项 - 力扣(LeetCode)

在这里插入图片描述
在这里插入图片描述
这个题使用双指针来说,方便很多,一个指针负责数组遍历,一个指针指向有效数组的最后一个位置。为了减少不必要的操作,我们这里做一些调整,令slow = 1,比较对象换做nums[slow -1] (这个操作真的很丝滑👍 )

先画个图吧:
在这里插入图片描述
代码展示:

    public static int removeDuplicates(int[] nums) {// 定义快慢指针int slow = 1;// 小心思// fast 遍历数组for(int fast = 0; fast < nums.length; fast++) {if (nums[fast] != nums[slow - 1]){nums[slow] = nums[fast];slow++;}}return slow;}

那你猜为什么令slow = 1 💡,你试着写一写 slow = 0的时候比较一下

看图容易一些
在这里插入图片描述
代码如下:

  public static int deleteRepeatVal(int[] nums) {// 定义快慢双指针int slow = 0;int fast = 0;while(fast < nums.length) {if (nums[slow] == nums[fast]){fast++;}else {nums[++slow] = nums[fast++];}}return slow + 1;}

总结

提示:双指针是常见的算法思想,建议重点掌握

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

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

相关文章

Node.js crypto模块 加密算法

背景 微信小程序调用飞蛾热敏纸打印机&#xff0c;需要进行参数sig签名校验&#xff0c;使用的是sha1进行加密 // 通过crypto.createHash()函数&#xff0c;创建一个hash实例&#xff0c;但是需要调用md5&#xff0c;sha1&#xff0c;sha256&#xff0c;sha512算法来实现实例的…

jq——点击显示隐藏来回切换、图片来回切换

案例展示 案例代码 <!DOCTYPE html> <html><head><meta charset"utf-8" /><title>显示隐藏</title></head><script src"js/jquery.js"></script><style>.switch {width: 50px;height: 50px;…

LNMT搭建部署

目录 一、概述 二、Nginx高级配置 三、搭建 一、概述 所谓的LNMT架构指的就是Linux操作系统上部署Nginx web服务器、MySQL数据库服务器、Tomcat中间件服务器。 二、Nginx高级配置 location 精确匹配 ^~ 不用正则的字符串匹配 …

惠普NS1020激光打印机碳粉警告提示及添加碳粉方法

本文也适用于惠普NS1020、1020c 和 1020w 系列打印机。 通过碳粉量指示灯检查碳粉量。 如果碳粉量是满的或指示器显示 1&#xff0c;可选择添加一个碳粉或者忽略不添加。如果碳粉量指示灯显示 2或 2 和碳粉量警告感叹号图标 &#xff0c;则表示碳粉量不足或严重不足&#xff0…

[Linux]命令行参数和进程优先级

[Linux]命令行参数和进程优先级 文章目录 [Linux]命令行参数和进程优先级命令行参数命令行参数的概念命令函参数的接收编写代码验证 进程优先级进程优先级的概念PRI and NI使用top指令修改nice值 命令行参数 命令行参数的概念 命令行参数是指用于运行程序时在命令行输入的参数…

vue三级市区联动

默认返回值格式&#xff1a;all:code、name都返回 name:只返回name code:只返回code&#xff0c;level&#xff1a;可设置显示层级 1&#xff1a; 省 2&#xff1a; 省、市 3&#xff1a; 省、市、区 v-model 默认值 可以是 name: [ "天津市", "天津市",…

爬虫逆向实战(二十三)--某准网数据

一、数据接口分析 主页地址&#xff1a;某准网 1、抓包 通过抓包可以发现数据接口是api_to/search/company_v2.json 2、判断是否有加密参数 请求参数是否加密&#xff1f; 通过查看“载荷”模块可以发现b参数和kiv参数是加密参数 请求头是否加密&#xff1f; 无响应是否加…

十四五双碳双控时代下的“低碳认证”

目录 前言 十四五双碳双控时代下的“低碳认证” 一、关于“低碳认证” 二、低碳认证优势 三、环境产品认证EPD 四、EPD相关运营机构 五、碳中和相关机构 六、EPD的认证流程 七、低碳产品认证认证流程和要求 八、相关机构认证证书样例 九、证书附件表 前言 通过本篇文…

柠檬水找零【贪心算法-】

柠檬水找零 在柠檬水摊上&#xff0c;每一杯柠檬水的售价为 5 美元。顾客排队购买你的产品&#xff0c;&#xff08;按账单 bills 支付的顺序&#xff09;一次购买一杯。 每位顾客只买一杯柠檬水&#xff0c;然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零&…

CSS按钮-跑马灯边框

思路很简单&#xff0c;实现方法有很多很多。但是大体思路与实现方法都类似&#xff1a;渐变色 动画&#xff0c;主要区别在动画的具体实现 0、HTML 结构 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><titl…

内网环境搭建-前篇

通常所说的内网渗透测试&#xff0c;很大程度上就是域渗透测试。搭建域渗透测试环境&#xff0c;在Windows的活动目录环境下进行一系列操作&#xff0c;掌握其操作方法和运行机制&#xff0c;对内网的安全维护有很大的帮助。常见的域环境是使用Windows Server2012 R2、Windows7…

大型集团企业数字化管控平台及信息化治理服务体系建设方案PPT

本资料来源公开网络&#xff0c;仅供个人学习&#xff0c;请勿商用&#xff0c;如有侵权请联系删除&#xff0c;更多浏览公众号&#xff1a;智慧方案文库 篇幅有限&#xff0c;无法完全展示&#xff0c;喜欢资料可转发评论&#xff0c;私信了解更多信息。