算法通关村第3关【白银】| 双指针思想

1. 双指针思想

双指针不仅指两个指针,也可以是两个变量,指向两个值。

有三种类型:

  • 快慢型:一前一后
  • 对撞型:从两端向中间靠拢
  • 背向型:从中间向两端分开

2. 删除元素专题

2.1原地移除元素

(1)快慢指针

思路:每次找到等于val就移动数组当val值比较多的时候时间复杂度太高,使用fast指针扫描等于val的值连续删除,当找到一段连续val中第一个不等于val的值的时候就覆盖实现批量删除。

class Solution {
    public int removeElement(int[] nums, int val) {
        int slow = 0;
        int fast = 0;
        int len = nums.length;
        while(fast < nums.length){
            if(nums[fast] == val){
                fast++;
                len--;
            }else{
                nums[slow++] = nums[fast++];
            }
        }
        return len;
    }
}

 (2)对撞指针

思路:两个指针一左一右,题目没有规定元素顺序,故当左指针指向要删除的值的时候就将右指针的值替换上来,右指针左移一位,实现删除一位的效果。

class Solution {
    public int removeElement(int[] nums, int val) {
        int right = nums.length - 1;
        int left = 0;
        int len = nums.length;
        while(left <= right){
            if(nums[left] != val){
                left++;
            }else{
                nums[left] = nums[right--];
                len--;
            }
        }
        return len;
    }
}

2. 2删除有序数组中的重复项

 思路:双指针,当一直重复fast指针就一直往后扫,直到扫到不重复的值,然后将不重复的值覆盖slow指向的重复的值,注意slow初始化为1,这样第一次进循环一定相等。

两个关键点:slow保留指针什么时候移动、fast指向怎么算符合条件的值

此处slow指针当元素开始不重复,即fast指向新值的时候移动

nums[fast] != nums[fast- 1]代表指向新值

class Solution {
    public int removeDuplicates(int[] nums) {
        int slow = 1;
        int fast = 1;
        while(fast < nums.length){
            if(nums[fast] != nums[fast- 1]){
                nums[slow++] = nums[fast];
            }
            fast++;
           
        }
        return slow;
    }
}

当删除使元素出现k个重复:

前k个不需要管,slow表示需要保留的值

当且仅当 nums[slow−k]=nums[fast]时,当前待检查元素 nums[fast]不应该被保留

(因为此时必然有 nums[slow−k]=nums[slow−(k-1)]=...=nums[fast])

例如:int[] arr = new int[]{1,1,1,2, 2,3,4,5,5,6,7,8,8,8,8,9};

此处slow指针当重复的元素不超过k个时移动

nums[fast] != nums[slow - k]代表fast指向的值在重复的k个元素范围之内

public static int removeDuplicatesk(int[] nums,int k) {
        int slow = k;
        int fast = k;
        while(fast < nums.length){
            if(nums[fast] != nums[slow - k]){
                nums[slow] = nums[fast];
                slow++;
            }
            fast++;
        }
        return slow;
    }

扩展:出现重复的元素都不要

此处slow指针当前后元素都只出现一次时移动

nums[fast] == nums[fast -1]判断元素是否重复了

public static int removeDuplicates0(int[] nums,int k) {
        int slow = 0;
        int fast = 1;
        int count = 0;//用来判断元素是否出现重复
        while(fast < nums.length){
            if (nums[fast] == nums[fast -1]){
                count++;
            } else if(nums[fast] != nums[fast -1]&&count!=0){
                //当元素出现不重复并且fast指向的是新值
                nums[slow] = nums[fast];
                //开始新的值重置
                count = 0;
            } else if (nums[fast] != nums[fast -1]&&count == 0){
                //当元素不重复,并且fast指向前也是不重复的值
                //这时slow保留指针才移动
                nums[++slow] = nums[fast];
            }
            fast++;
        }
        return count == 0 ? slow+1 : slow;
    }

3.元素奇偶移动

思路:对撞型双指针,当left指到奇数,right指到偶数就相互交换。需要注意一些边界处理细节,避免数组越界情况。

class Solution {
    public int[] sortArrayByParity(int[] nums) {
        int left = 0;
        int right = nums.length - 1;
        while(left<right){
            while(left<right && nums[left] % 2 == 0){
                left++;
            }
            while(left<right && nums[right] % 2 != 0){
                right--;
            }
            if(left<right){
                int t = nums[left];
                nums[left] = nums[right];
                nums[right] = t;
                left++;
                right--;
            }
            
        }
        return nums;
    }
}

4.数组轮转

思路:

方法一、暴力解法,找到开始轮转的数,然后剪切拼接到新的数组。需要注意k可能比数组长度大得取模

class Solution {
    public void rotate(int[] nums, int k) {
        int[] res = new int[nums.length];
        int left = 0;
        int right = nums.length;
        int kk = k;
        while( k % nums.length>0){
            right--;
            k--;
        }
        int i = 0;
        for(;i<kk%nums.length;i++){
            res[i] = nums[right%nums.length];
            right++;
        }
        for(;i<nums.length;i++){
            res[i] = nums[left++];
        }
        System.arraycopy(res, 0, nums, 0, nums.length);
    }
}

 优化:i+k将当前元素往右移动k,取模避免数组越界

class Solution {
    public void rotate(int[] nums, int k) {
        int n = nums.length;
        int[] newArr = new int[n];
        for (int i = 0; i < n; ++i) {
            newArr[(i + k) % n] = nums[i];
        }
        System.arraycopy(newArr, 0, nums, 0, n);
    }
}

方法二、翻转,往右轮转结果就是数组后面的值移动到了前面,进行一次整体翻转,再在k处分成左右两部分再次翻转就是往右轮转的最终效果了。

class Solution {
    public void rotate(int[] nums, int k) {
        revers(nums,0,nums.length-1);
        revers(nums,0,(k%nums.length)-1);
        revers(nums,(k%nums.length),nums.length-1);
    }

    public void revers(int[] nums,int l,int r){
        while(l<r){
            int t = nums[l];
            nums[l] = nums[r];
            nums[r] = t;
            l++;
            r--;
        }
    }
}

5.数组的区间

 思路:题目的意思是说不连续递增的就断开输出

双指针,slow指向区间起始,fast负责寻找到区间结束

class Solution {
    public List<String> summaryRanges(int[] nums) {
        List<String> res = new ArrayList<>();
        int slow = 0;
        int fast = 0;
        while(fast<nums.length){
            if(fast + 1 == nums.length || nums[fast] + 1 != nums[fast+1]){
                if(slow == fast){
                    res.add("" + nums[slow]);
                }else{
                    res.add(nums[slow] + "->" + nums[fast]);
                }
                slow = fast+1;
            }
            fast++;
        }
        return res;
    }
}

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

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

相关文章

Docker安装基础使用练习

目录 1、安装Docker-CE 1&#xff09;简单使用yum方式安装 ! 2&#xff09;配置镜像加速&#xff1a; 2、下载系统镜像&#xff08;Ubuntu、 centos&#xff09; 1&#xff09;先查看我们所需的镜像有哪些版本。使用search命令&#xff01; 2&#xff09;下载镜像使用的是pul…

nestjs 基础、使用 passport 来进行鉴权

回顾一些定义 NestJS 部分 Module 模块结构 模块是一个图状引用关系。 模块的实例化有三种模式。默认情况是 singletones 模式&#xff0c;也就是模块可能被引用&#xff0c;但不同的引用处拿的是同一个共享实例&#xff0c;也就是说一个进程有一个唯一的实例被共享。 模块&a…

uni-app自定义多环境配置,动态修改appid

背景 在企业级项目开发中&#xff0c;一般都会分为开发、测试、预发布、生产等多个环境&#xff0c;在工程化中使用不同的打包命令改变环境变量解决不同环境各种变量需要手动修改的问题&#xff0c;比如接口请求地址&#xff0c;不同环境的请求路径前缀都是不同的。在使用uni-…

虚拟现实与增强现实技术的商业应用

章节一&#xff1a;引言 随着科技的不断发展&#xff0c;虚拟现实&#xff08;Virtual Reality&#xff0c;简称VR&#xff09;与增强现实&#xff08;Augmented Reality&#xff0c;简称AR&#xff09;技术正日益成为商业领域中的重要创新力量。这两种技术为企业带来了前所未…

深入源码分析kubernetes informer机制(四)DeltaFIFO

[阅读指南] 这是该系列第四篇 基于kubernetes 1.27 stage版本 为了方便阅读&#xff0c;后续所有代码均省略了错误处理及与关注逻辑无关的部分。 文章目录 client-go中的存储结构DeltaFIFOdelta索引 keyqueue push操作delta push 去重 queue pop操作 总结 client-go中的存储结构…

CCLINK转MODBUS-TCP网关cclink通讯接线图 终端电阻

大家好&#xff0c;今天我们要聊的是生产管理系统中的CCLINK和MODBUS-TCP协议&#xff0c;它们的不同使得数据互通比较困难&#xff0c;但捷米JM-CCLK-TCP网关的出现改变了这一切。 1捷米JM-CCLK-TCP是一款自主研发的CCLINK从站功能的通讯网关&#xff0c;它的主要功能是将各种…

PS丢失d3dcompiler_47.dll文件怎么办(附详细修复方法)

我们在安装PS等软件的时候&#xff0c;有可能安装完之后出现以下问题&#xff08;特别是win10或者win11系统&#xff09; 错误&#xff1a; 打开PS的时候出现这个错误&#xff1a;无法启动此程序&#xff0c;因为计算机中丢失D3DCOMPILER_47.dll。尝试重新安装该程序以解决此问…

[Go版]算法通关村第十一关青铜——理解位运算的规则

目录 数字在计算机中的表示&#xff1a;机器数、真值对机器数进一步细化&#xff1a;原码、反码、补码为何会有原码、反码和补码为何计算机中的按位运算使用的是补码&#xff1f;位运算规则与、或、异或和取反移位运算移位运算与乘除法的关系位运算常用技巧⭐️ 操作某个位的数…

20W IP网络吸顶喇叭 POE供电吸顶喇叭

SV-29852T 20W IP网络吸顶喇叭产品简介 产品用途&#xff1a; ◆室内豪华型吸顶喇叭一体化网络音频解码扬声器&#xff0c;用于广播分区音频解码、声音还原作用 ◆应用场地如火车站、地铁、教堂、工厂、仓库、公园停车场等&#xff1b;室内使用效果均佳。 产品特点&#xff…

linux——MongoDB服务

目录 一、MongoDB概述 相关概念 特性 应用场景 二、目录结构 三、默认数据库 admin local config 四、数据库操作 库操作 文档操作 五、MongoDB数据库备份 一、备份 mongodump mongoexport 二、恢复 mongorestore mongoimport ​编辑 一、MongoDB概述 MongoDB是…

04-微信小程序常用组件-基础组件

04-微信小程序常用组件-基础组件 文章目录 基础内容icon 图标案例代码 text 文本案例代码 progress 进度条案例代码 微信小程序包含了六大组件&#xff1a; 视图容器、 基础内容、 导航、 表单、 互动和 导航。这些组件可以通过WXML和WXSS进行布局和样式设置&#xff0c…

数据库相关面试题

巩固基础&#xff0c;砥砺前行 。 只有不断重复&#xff0c;才能做到超越自己。 能坚持把简单的事情做到极致&#xff0c;也是不容易的。 mysql怎么优化 : MySQL的优化可以从以下几个方面入手&#xff1a; 数据库设计优化&#xff1a;合理设计表结构&#xff0c;选择合适的数…

Windows下问题定位

1、内存相关知识点&#xff1b; 1&#xff09;windows下32位进程&#xff0c;用户态为2G内存&#xff0c;内核态也为2G内存&#xff1b;却别于linux操作系统&#xff1b; 备注&#xff1a;可以通过命令行与管理员权限&#xff0c;启动3G的用户态空间&#xff0c;但是部…

数据结构的树存储结构

数据结构的树存储结构 之前介绍的所有的数据结构都是线性存储结构。本章所介绍的树结构是一种非线性存储结构&#xff0c;存储的是具有“一对多”关系的数据元素的集合。 (A) (B) 图 1 树的示例 图 …

同伦问题与同伦算法

同伦问题 据我所知&#xff0c;这篇博客是CSDN上少数几篇讲同伦算法的博客之一考虑同伦算法的目的 扩大初值选取范围解决非线性代数方程组的全部解计算问题 同伦算法中的基本概念 考虑求的解人为地引入参数t,构造一个函数族使得 同时假设的解已知&#xff0c;从出发可以求解对…

3 Python的数据类型

概述 在上一节&#xff0c;我们介绍了Python的基础语法&#xff0c;包括&#xff1a;编码格式、标识符、关键字、注释、多行、空行、缩进、引号、输入输出、import、运算符、条件控制、循环等内容。Python是一种动态类型的编程语言&#xff0c;这意味着当你创建一个变量时&…

星际争霸之小霸王之小蜜蜂(三)--重构模块

目录 前言 一、为什么要重构模块 二、创建game_functions 三、创建update_screen() 四、修改alien_invasion模块 五、课后思考 总结 前言 前两天我们已经成功创建了窗口&#xff0c;并将小蜜蜂放在窗口的最下方中间位置&#xff0c;本来以为今天将学习控制小蜜蜂&#xff0c;结…

<CodeGeeX>基于大模型的全能AI编程助手

CodeGeex官网 智谱AI官网 CodeGeex是由清华大学 KEG 实验室和智谱 AI 公司于2023共同训练的代码生成模型 CodeGeeX 开发的AI助手。它基于深度学习技术&#xff0c;能够针对用户的问题和要求提供适当的答复和支持。CodeGeex的功能包括代码生成、自动添加注释、代码翻译以及智能问…

php base64转图片保存本地

调用函数 public function base64(){$img $this->request->param(img);$img data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAkACQAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIy…

Android开发之性能优化:过渡绘制解决方案

1. 过渡绘制 屏幕上某一像素点在一帧中被重复绘制多次&#xff0c;就是过渡绘制。 下图中多个卡片跌在一起&#xff0c;但是只有第一个卡片是完全可见的。背后的卡片只有部分可见。但是Android系统在绘制时会将下层的卡片进行绘制&#xff0c;接着再将上层的卡片进行绘制。但其…