算法通关村第三关——双指针的妙用

双指针思想

快慢指针

        所谓的双指针其实就是两个变量。双指针思想简单好用,在处理数组、字符串等场景下很常见。看个例子,从下面序列中删除重复元素[1,2,2,2,3,3,3,5,5,7,8],重复元素只保留一个。删除之后的结果应该为[1,2,3,5,7,8]。我们可以在删除第一个2时将将其后面的元素整体向前移动一次,删除第二个2时再将其后的元素整体向前移动一次,处理后面的3和5都一样的情况,这就导致我们需要执行5次大量移动才能完成,效率太低。如果使用双指针可以方便的解决这个问题,如图:

image.png

        首先,定义两个指针slow、fast。slow表示当前位置之前的元素都是不重复的,而fast则一直向后查找,直到找到与slow 位置不一样的(找到不重复的元素)。找到之后就将slow 向后移动一个位置,并肩arr[fast] 复制给arr[slow],之后fast继续向后找,循环执行。找完之后,slow以及之前的元素就是单一的了。这样就可以使用一轮移动解决问题。

对撞型指针 

        上面这种一个指针在前,一个指针在后的方式也称为快慢指针,有些场景需要从两端向中间轴,这种就称为对撞型指针或者叫相向型指针。很多 题目也会用到

背向型指针

        还有一种比较少见的背向型,就是从中间向两边走。这三种类型其实非常简单看的只是两个指针是一起向前走 (相亲相爱一起走),还是从两头向中间走 (冲破干难万险来爱你),还是从中间向两头走 (缘分已尽,就此拜拜)。 

删除元素专题 

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

题目

         给你一个数组nums 和一个值 val ,你需要原地移除所有数字相等的val的元素,并返回移除后数组的新长度。

要求;

        不要使用额外的数组空间,你必须仅使用O(1) 额外空间 并原地修改输入数组。元素的顺序可以改变,你不需要考虑数组汇总超出新长度后面的元素

例子

        输入: nums = [3,2,2,3] , val = 3

        输出:2

        输入:nums=[0,1,2,2,3,0,4,2] , val = 2

        输出:5

关键点

        在删除的时候,从删除位置开始的所有元素都要向前移动,所以这题的关键是如何有很多值为val的元素的时候,避免反复向前移动。 

方法一、快慢指针

思想

        整体思想就是快慢指针。

        定义两个指针slow和fast,初始值都是0.

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

        以fast为遍历变量,数组遍历的时候,fast不断向后移动:

                如果nums[fast] 的值不为val ,则将其移动到nums[slow++]处

                如果nums[fast] 的值为val,则fast继续向前移动,slow先等待。

        图示:

image.png

        这样一来,前半部分是有效的,后半部分是无效的 

代码实现
    /**
     * 给你一个数组nums 和一个值 val ,你需要原地移除所有数字相等的val的元素,并返回移除后数组的新长度
     * 要求:
     *  不要使用额外的数组空间,你必须仅使用O(1) 额外空间 并原地修改输入数组。元素的顺序可以改变,你不需要考虑数组汇总超出新长度后面的元素
     * @param nums 给定的数组
     * @param val 要删除的值
     * @return 删除数组元素后的新长度
     */
    public static int removeElements(int [] nums,int val){
        // slow 表示有效的下标(未被删除的下标)
        int slow = 0;
        for (int fast = 0; fast < nums.length; fast++) {
            if (nums[fast] != val){
                nums[slow] = nums[fast];
                // 3  2  2  3
                // 3
                // nums[0] = num[1]
                // nums[1] = num[2]
                slow++;
            }
        }
        return slow;
    }

方法二、对撞双指针

        对撞指针,也叫交换移除。核心思想是:从右侧找到不是val的值    来顶替(通过交换、覆盖的方式) 左侧是val的值(如果右侧找到为val的值,就将其忽略,直接right--跳过),最后返回左侧不是val的值 。

        以nums=[0,1,2,2,3,0,4,2],val = 2 为例:

image.png

        当left == right时,left以及左侧的就是删除指定元素2 后的所有元素了 

实现代码
    public static int getremoveElementsSize(int [] nums , int val ){
        int left;
        int right = nums.length -1 ;
        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 ,请你原地删除重复出现的元素,使每个元素只出现一次,返回删除后数组的新长度。

要求:

        不要使用额外的数组空间,你不需要在原地修改输入数组 并在使用O(1)额外空间的条件下完成

代码实现
    /**
     * 给你一个   有序   数组 nums ,请你原地删除重复出现的元素,使每个元素只出现一次,返回删除后数组的新长度。
     * 要求:
     *      不要使用额外的数组空间,你不需要在原地修改输入数组  并在使用O(1)额外空间的条件下完成
     * @param nums  有序数组
     * @return 数组新长度
     */
    public static  int removeCommonElements(int [] nums){
        // slow 表示可以放入新元素的位置(下标),元素为0的不管
        int slow = 1;
        // 循环起到了快指针的作用
        for (int fast = 1 ; fast < nums.length ; fast ++){
            if (nums[fast] != nums[slow -1]){
                nums[slow] = nums[fast];
                slow++;
            }
        }
        return slow;
    }
 

 

 

 

 

 

 

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

应用程序接口(API)安全的入门指南

本文简单回顾了 API 的发展历史&#xff0c;其基本概念、功能、相关协议、以及使用场景&#xff0c;重点讨论了与之相关的不同安全要素、威胁、认证方法、以及十二项优秀实践。 根据有记录的历史&#xff0c;随着 Salesforce 的销售自动化解决方案的推出&#xff0c;首个 Web A…

HCIP期中实验

考试需求 1 、该拓扑为公司网络&#xff0c;其中包括公司总部、公司分部以及公司骨干网&#xff0c;不包含运营商公网部分。 2 、设备名称均使用拓扑上名称改名&#xff0c;并且区分大小写。 3 、整张拓扑均使用私网地址进行配置。 4 、整张网络中&#xff0c;运行 OSPF 协议…

PostgreSQL中如何配置Huge page的数量

在了解如在PG中如何配置大页之前&#xff0c;我们先要对大页进行一定的了解&#xff0c;为什么要配置大页&#xff0c;配置大页的好处有哪些。 我们日常的操作系统中&#xff0c;程序不直接使用内存&#xff0c;而是使用虚拟内存地址来处理内存分配&#xff0c;避免计算的复杂…

1.3 eureka+ribbon,完成服务注册与调用,负载均衡源码追踪

本篇继先前发布的1.2 eureka注册中心&#xff0c;完成服务注册的内容。 目录 环境搭建 采用eurekaribbon的方式&#xff0c;对多个user服务发送请求&#xff0c;并实现负载均衡 负载均衡原理 负载均衡源码追踪 负载均衡策略 如何选择负载均衡策略&#xff1f; 饥饿加载…

windows下tomcat无故宕机,检测http或https服务,并自动重启Tomcat服务

一、问题描述及解决原理 把项目发布到windows服务器中&#xff0c;如tomcat工程不稳定&#xff0c;会有无故宕机的问题。如果通过程序无法解决&#xff0c;并且重启tomcat服务能够生效的话&#xff0c;可以做一个自动检测并重启的脚本。 脚本通过检测tomcat对应的工程链接&…

一文了解Angular、React 和 Vue.js的区别

前端开发人员在开始一个新项目时首先要回答的问题是&#xff1a;我应该选择哪个框架&#xff1f; 哪个框架更适合我的需求&#xff1f; 在本文中&#xff0c;我们将向您快速概述当前使用的最常见的前端框架&#xff0c;旨在帮助您选择最能满足您需求的框架。这些框架是 Angular…

【雕爷学编程】Arduino动手做(177)---ESP-32 掌控板

37款传感器与执行器的提法&#xff0c;在网络上广泛流传&#xff0c;其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块&#xff0c;依照实践出真知&#xff08;一定要动手做&#xff09;的理念&#xff0c;以学习和交流为目的&am…

PHP8的常量-PHP8知识详解

常量和变量是构成PHP程序的基础&#xff0c;在PHP8中常量的这一节中&#xff0c;主要讲到了定义常量和预定义常量两大知识点。 一、定义常量 定义常量也叫声明常量。在PHP8中&#xff0c;常量就是一个标识符&#xff08;名字&#xff09;&#xff0c;一旦定义&#xff08;声明&…

Java常用API:Math、Syetem、Runtime、BigDecimal

Math类 //目标:了解下Nath类提供的常见方法。 // 1、public static int abs(int a):取绝对值&#xff08;拿到的结果一定是正数&#xff09; //public static double abs(double a) system.out.println(Math.abs(-12)); // 12 system.out.println(Math.abs(123));// 123 system…

VScode远程不用再输入密码操作

安装插件remote development 1.先检查自己电脑上有没有生成一对公钥和私钥。&#xff08;一般会在这个目录&#xff09; 如果没有的话就自己生成一下。 打开命令行输入以下命令 ssh-keygen -t rsa2.在虚拟机中先看一下有没有公钥和私钥。如果没有的话就自己生成一下。 打开…

华为数通HCIA-网络参考模型(TCP/IP)

网络通信模式 作用&#xff1a;指导网络设备的通信&#xff1b; OSI七层模型&#xff1a; 7.应用层&#xff1a;由应用层协议&#xff08;http、FTP、Telnet.&#xff09;为应用程序产生对应的数据&#xff1b; 6.表示层&#xff1a;将应用层产生的数据转换成网络设备看得懂…

STM32 USB使用记录:HID类设备(后篇)

文章目录 目的基础说明项目构建与代码调整接收发送代码与测试示例链接报告描述符总结 目的 接上篇&#xff1a; 《STM32 USB使用记录&#xff1a;HID类设备&#xff08;前篇&#xff09;》 USB HID 类的设备有个比较大的好处是大部分时候接入主机中都是可以免驱使用的。这篇文…

Shell脚本实现分库分表操作

目录 一&#xff0c;分库备份 二&#xff0c;分库操作 三&#xff0c;分库分表备份 四&#xff0c;备份还原 一&#xff0c;分库备份 #!/bin/bash mysql_cmd-uroot -pzly666666 bak_path/backup/db [ -d ${bak_path} ] || mkdir -p ${bak_path}mysql ${mysql_cmd} -e show…

【图论】BFS中的最短路模型

算法提高课笔记 目录 单源最短路迷宫问题题意思路代码 武士风度的牛题意思路代码 抓住那头牛题意思路代码 多源最短路矩阵距离题意思路代码 双端队列BFS电路维修题意思路代码&#xff08;加了注释&#xff09; BFS可以解决边权为1的最短路问题&#xff0c;下面是相关例题 单源…

python-面向对象.继承

继承 1.单继承 父类也叫基类 子类也叫派生类 如下所示&#xff0c;继承的关系&#xff1a; 继承的书写格式&#xff1a; class 子类(父类): 方法 实例&#xff1a; class Animal: def eat(self): print("-----吃-------") def drink(self): print("-----喝…

【100天精通python】Day21:文件及目录操作_文件的权限处理和批量处理

目录 专栏导读 1. 文件的权限处理 1.1 查询文件权限 1.2 修改文件权限 2 文件的批量处理 2.1 使用os模块和os.listdir()函数 2.2 使用glob模块 2.3 使用shutil模块 2.3.1 批量复制文件 2.3.2 批量移动文件 2.3.3 批量删除文件 2.3.4 批量创建目录 专栏导读 专栏订阅…

聊聊拉长LLaMA的一些经验

Sequence Length是指LLM能够处理的文本的最大长度&#xff0c;越长&#xff0c;自然越有优势&#xff1a; 更强的记忆性。更多轮的历史对话被拼接到对话中&#xff0c;减少出现遗忘现象 长文本场景下体验更佳。比如文档问答、小说续写等 当今开源LLM中的当红炸子鸡——LLaMA…

[Docker实现测试部署CI/CD----相关服务器的安装配置(1)]

目录 0、CI/CD系统最终架构图规划IP地址 1、git配置Git下载pycharm配置gitidea配置git 2、GitLab安装与配置主机要求拉取镜像定义 compose.yml启动gitlab浏览器访问并修改密码查看登录密码修改密码 3、SonarQube 安装与配置拉取镜像修改虚拟内存的大小启动SonarQube登录 SonarQ…

2023 蓝桥杯真题B组 C/C++

https://www.dotcpp.com/oj/train/1089/ 题目 3150: 蓝桥杯2023年第十四届省赛真题-冶炼金属 题目描述 小蓝有一个神奇的炉子用于将普通金属 O 冶炼成为一种特殊金属 X。这个炉子有一个称作转换率的属性 V&#xff0c;V 是一个正整数&#xff0c;这意味着消耗 V 个普通金 属 O…

价值 1k 嵌入式面试题-计算机网络 OSI

开门见山 请讲下 OSI 各层协议的主要功能&#xff1f; 常见问题 回答不系统回答不确切无法和实际网络协议做关联对应 答题思路 OSI 代表了开放互联系统中信息从一台计算机的一个软件应用流到另一个计算机的另一个软件应用的参考模型 OSI 包含 7 层&#xff0c;每一层负责特…
最新文章