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

news2024/9/25 17:14:44

文章目录

  • 前言
  • 什么是数组双指针
  • 数组中删除元素专题
    • 原地移除所有等值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.coloradmin.cn/o/930230.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于Java+SpringBoot+Vue前后端分离在线考试与学习交流网页平台设计和实现

博主介绍&#xff1a;✌全网粉丝30W,csdn特邀作者、博客专家、CSDN新星计划导师、Java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专…

象小朋友学识字一样建构战略

战略认知派: 就像小孩子学识字的过程一样【安志强趣讲268期】 趣讲大白话&#xff1a;提高认知中长大 **************************** 基于认知心理学 战略的形成是认知构建的过程 最找连战略这个词都不一定知道 慢慢有些概念 慢慢形成整体的认知 战略认知派分两个分支 第一分支…

VMware安装OpenEuler

VMware安装OpenEuler 需要考虑的因素&#xff1a; 安装系统的用途&#xff1a;桌面开发、服务器、Linux学习使用&#xff1b;磁盘分区规划&#xff1a;最小120G&#xff0c;划分 boot, swap, 根分区等网络&#xff1a;是否对外提供服务&#xff08;NAT模式、桥接模式、仅主机…

ModaHub魔搭社区:WinPlan经营大脑数据采集

目录 WinPlan经营大脑数据采集介绍 WinPlan经营大脑数据采集模版 WinPlan经营大脑数据采集介绍 基于指标、维度来创建业务表单,通过业务表单的形式来采集实际数据,最终生成企业统一的经营数据库。由于需要客户创建数据采集模版(业务流程),然后可以基于各个业务模版作为…

WebSocket详解以及应用

&#x1f61c;作 者&#xff1a;是江迪呀✒️本文关键词&#xff1a;websocket、网络、长连接、前端☀️每日 一言&#xff1a;任何一个你不喜欢而又离不开的地方&#xff0c;任何一种你不喜欢而又无法摆脱的生活&#xff0c;都是监狱&#xff01; 一、前言 我们在…

定州市社会保险待遇手机app-定州社会保障

社会保险的缴纳主要包括养老保险、医疗保险、生育保险&#xff0c;单位职工还有工伤保险和失业保险的缴纳&#xff0c;社会保险的缴纳一般都在当地人力资源和社会保障部门&#xff0c;在定州&#xff0c;社会保险登记的流程是怎样走的&#xff1f;下面由法律指南小编为大家解答…

改进YOLO系列:6.添加ECA注意力机制

添加ECA注意力机制 1. ECA注意力机制论文2. ECA注意力机制原理3. ECA注意力机制的配置3.1common.py配置3.2yolo.py配置3.3yaml文件配置1. ECA注意力机制论文 论文题目:ECA-Net: Efficient Channel Attention for Deep Convolutional Neural Networks 论文链接:ECA-N…

oracle 12c怎样修改varchar2允许的最大长度

12C单实例测试&#xff0c;varchar2在早期版本中最大长度限制为4000&#xff0c;当字段长度指定的比较长的时候会报错&#xff1a;ORA-00910: specified length too long for its datatype。 早期版本中虽然SQL数据类型限制为4000&#xff08;如表中的列的varchar2类型&#x…

抖音web频道爬虫

抖音web频道爬虫代码&#xff1a; <?php header(Content-Type:application/json; charsetutf-8);//抖音频道爬虫class DouyinChannel{private $app_id 1;private $spider_code 1;private $channels [["channel_name" > "热点","url"…

Java实现自定义注解

前言 &#xff08;1&#xff09;Java实现自定义注解其实很简单&#xff0c;跟类定义差不多&#xff0c;只是属性的定义可能跟我们平时定义的属性略有不同&#xff0c;这里会给大家详解&#xff0c;先来看代码&#xff1a; Target(ElementType.FIELD) Retention(RetentionPoli…

iOS App的设计规范

iOS App 的设计规范是苹果公司为开发人员和设计师提供的一系列准则和建议&#xff0c;旨在确保应用在 iOS 设备上的外观、交互和用户体验保持一致。以下是一些常见的 iOS App 设计规范要点&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包…

LEADTOOLS V22 for Python -Crack

LEAD Technologies Inc 是面向所有主要平台和编程语言的应用程序开发的人工智能 SDK 的领先提供商&#xff0c;很高兴地宣布在其最新的 LEADTOOLS 版本 22 更新中添加了完整的 Python 支持。 Python是一种动态的高级编程语言&#xff0c;广泛应用于科学计算、数据分析、人工智…

似懂非懂的 AspectJ

今天想和小伙伴们聊一下我们在使用 Spring AOP 时&#xff0c;一个非常常见的概念 AspectJ。 1. 关于代理 小伙伴们知道&#xff0c;Java 23 种设计模式中有一种模式叫做代理模式&#xff0c;这种代理我们可以将之称为静态代理&#xff0c;Spring AOP 我们常说是一种动态代理…

R语言常用基本函数,含实例:万字总结

目录 vector:创建向量&#xff08;默认填充0&#xff0c;空字符&#xff0c;FALSE&#xff09; data.frame :可以看作由多个向量组成的表格&#xff0c;每个向量代表表格的一列数据 sequence:创建序列(可以简写为seq) dim:获取矩阵或数组的维度信息 length subset&#x…

优思学院|传统流水线生产与单元式生产的差异与优势对比

在制造业领域&#xff0c;生产方式的选择对于生产效率和产品质量至关重要。传统流水线生产和精益生产中的单元式生产是两种常见的生产模式&#xff0c;它们在工作方式、优势以及适用情境上存在着显著的差异。本文将对传统流水线生产和单元式生产进行比较&#xff0c;并探讨它们…

“探索Spring与MyBatis集成的最佳实践与技巧“

目录 引言&#xff1a;1.Spring与MyBatis集成的基本配置2.Spring aop集成pagehelper插件总结附带内容&#xff1a; 引言&#xff1a; 在现代的软件开发中&#xff0c;Spring和MyBatis是两个非常流行的框架。Spring提供了强大的依赖注入和面向切面编程的功能&#xff0c;而MyBa…

炫酷前端页面,鼠标点击特效

最近发现了两个好看的鼠标点击特效&#xff0c;收藏起来用作学习使用&#xff0c;以及更方便的利用 一、鼠标点击弹出爱心 效果图 html源码如下&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><m…

应知道的python基础知识

1、运算符 2、特殊情况下的逻辑运算 3、循环中的else 3.1 while else 3.2 for else 4、列表相关操作 列表的相关操作 4.1增(append, extend, insert) 通过append可以向列表添加元素:列表.append(新元素数据)通过extend可以将另一个列表中的元素逐一添加到列表中:列表.exte…

【推荐】Spring与Mybatis集成

目录 1.概述 2.集成 2.1代码演示&#xff1a; 3.整合 3.1概述 3.2 进行整合分页 接着上两篇&#xff0c;我已经写了Mybatis动态之灵活使用&#xff0c;mybatis的分页和特殊字符的使用方式接下来把它们集成起来&#xff0c;是如何的呢&#x1f447;&#x1f447;&#x1…

深入理解linux内核--系统启动

史前时代&#xff1a;BIOS 计算机在加电的那一刻几乎是毫无用处的&#xff0c;因为RAM芯片中包含的是随机数据&#xff0c;此时还没有操作系统在运行。 在开始启动时&#xff0c;有一个特殊的硬件电路在CPU的一个引脚上产生一个RESET逻辑值。 在RESET产生以后&#xff0c;就把…