[算法] 优先算法(一): 双指针算法(上)

🌸个人主页:https://blog.csdn.net/2301_80050796?spm=1000.2115.3001.5343
🏵️热门专栏:🍕 Collection与数据结构 (91平均质量分)https://blog.csdn.net/2301_80050796/category_12621348.html?spm=1001.2014.3001.5482
🧀Java EE(94平均质量分) https://blog.csdn.net/2301_80050796/category_12643370.html?spm=1001.2014.3001.5482
🍭MySql数据库(93平均质量分)https://blog.csdn.net/2301_80050796/category_12629890.html?spm=1001.2014.3001.5482
感谢点赞与关注~~~
今天开始,算法专栏正式开始更新,欢迎订阅~~
在这里插入图片描述

目录

  • 1. 概述
    • 1.1 对撞指针
    • 1.2 快慢指针
  • 2. 移动零(难度:🟢1度)
  • 3. 复写零(难度:🟡3度)
  • 4. 快乐数(难度:🔵2度)
  • 5. 盛水最多的容器(难度:🟡3度)

1. 概述

常见的双指针算法有两种:一种是对撞指针,一种是快慢指针.

1.1 对撞指针

对撞指针,也叫左右指针.一般用于顺序结构中.

  • 对撞指针从两端向中间移动,一个指针从最右边开始,一个指针从最左边开始.
  • 对撞指针的最终结果就是:left == right两个指针相遇或者left >= right两个指针刚好错开,也可能在循环遍历的途中找到结果直接break掉.

1.2 快慢指针

又称为龟兔赛跑算法,基本思想就是在一个链表或者序列结构上定义两个移动速度不同的指针,一个走得快,一个走的慢,最常用的就是一个指针移动一位,另一个指针移动两位.
这种算法在解决环形结构的时候非常有用.如果我们要研究的问题出现循环往复的情况时,均可考虑使⽤快慢指针的思想.

2. 移动零(难度:🟢1度)

OJ链接

  • 题目描述

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

  • 算法原理
    本题最核心的原理就是:数组区间划分.
    我们可以定义两个指针,一个是cur,一个是dest,dest用来记录最后一个非零数字的位置,cur用来遍历数组.在划分的时候,[0,dest]区间全部是非零元素,[dest+1,cur]区间中全部是0元素,[cur+1,array.length]区间是未处理的元素,这样就使用两个指针把这个数组分段为了三个区间.
  • 解决步骤
    1. 定义cur = 0定义dest = 0,之后cur向后移动.
    2. cur移动到一个元素不为0的时候,交换destcur位置的元素.之后dest++.
    3. cur遇到一个为0的元素的时候,不做任何处理,cur直接++.
    4. 直到cur移动到数组的末尾,结束循环.
  • 代码编写
class Solution {public void moveZeroes(int[] nums) {int cur = 0;int dest = 0;while(cur < nums.length){if(nums[cur] == 0){cur++;}else{int tmp = nums[dest]; nums[dest] = nums[cur];nums[cur] = tmp;cur++;dest++;}}}
}

3. 复写零(难度:🟡3度)

OJ链接

  • 题目描述

给你一个长度固定的整数数组 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]

  • 算法原理
    如果使用从前向后复写的思路来解决的话,这样就会使得0被复写的时候,后面一个未被复写的元素被覆盖掉.
    所以我们采用从后向前复写的方法,但是如果从后向前复写的话,就必须最后一个被复写的对象.
    找到最后一个被复写的对象,我们就可以采用从前向后模拟指针移动方式来找到.
  • 算法步骤
    1. 初始化cur = 0 dest = 0.
    2. 找到最后一个复写的数字.
    3. cur遍历数组,当cur遇到非0的数字的时候,dest向后移动1位,当cur遇到0的时候,cur向后移动两位,直到dest走到数组的末尾的时候,cur停止遍历,此时cur 的位置就是最后一个要复写的数字.
    4. 判断dest位置的情况,如果dest位置在数组越界一个下标的位置的时候:我们就可以让n-1位置的值修改为0,之后dest-=2,cur-=1.之所以会出现越界的情况,是因为cur最后一个遍历到的元可能是0,这就使得dest元素向后移动了2个位置,导致数组越界.
    5. dest从前向后移动,当cur遇到非0的时候,dest的位置就重写一次cur位置的元素,如果遇到0,就重写两次0,直到dest走到数组的首位.
  • 代码编写
class Solution {public void duplicateZeros(int[] arr) {int cur = 0;int dest = -1;//找到最后一个复写的元素while(cur < arr.length){if(arr[cur] == 0){dest+=2;}else{dest++;}if(dest >= arr.length-1){break;}cur++;}//处理边界越界情况if(dest == arr.length){arr[arr.length-1] = 0;dest-=2;cur--;}//向前移动完成复写操作while(cur >= 0){if(arr[cur] != 0){arr[dest]=arr[cur];cur--;dest--;}else{arr[dest] = 0;dest--;arr[dest] = 0;dest--;cur--;}}}
}

4. 快乐数(难度:🔵2度)

OJ链接

  • 题目描述

编写一个算法来判断一个数 n 是不是快乐数。
「快乐数」 定义为:
对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。
然后重复这个过程直到这个数变为 1,也可能是 无限循环 但始终变不到 1。
如果这个过程 结果为 1,那么这个数就是快乐数。
如果 n 是 快乐数 就返回 true ;不是,则返回 false 。
示例 1:
输入:n = 19
输出:true
解释:
12 + 92 = 82
82 + 22 = 68
62 + 82 = 100
12 + 02 + 02 = 1
示例 2:
输入:n = 2
输出:false

  • 算法原理
    为了⽅便叙述,将「对于⼀个正整数,每⼀次将该数替换为它每个位置上的数字的平⽅和」这⼀个操作记为x 操作
    题⽬告诉我们,当我们不断重复x 操作的时候,计算⼀定会「死循环」,死的⽅式有两种:
    ▪ 情况⼀:⼀直在1 中死循环,即1 -> 1 -> 1 -> 1
    ▪ 情况⼆:在历史的数据中死循环,但始终变不到1
    由于上述两种情况只会出现⼀种,因此,只要我们能确定循环是在「情况⼀」中进⾏,还是在「情
    况⼆」中进⾏,就能得到结果。
    在这里插入图片描述

如果这道题不会出现死循环,这道题就会变得非常麻烦,难度至少到达4度,所以题目中规定一定会出现死循环其实是帮我们降低了难度.
这里我们使用使用快慢双指针算法,但是这里 的双指针并不是像上面数组的下标,更不是像链表中的两个引用对象,而是数字结果本身.
根据上述的题⽬分析,我们可以知道,当重复执⾏x 的时候,数据会陷⼊到⼀个「循环」之中。⽽「快慢指针」有⼀个特性,就是在⼀个圆圈中,快指针总是会追上慢指针的,也就是说他们总会
相遇在⼀个位置上。如果相遇位置的值是1 ,那么这个数⼀定是快乐数;如果相遇位置不是1
的话,那么就不是快乐数

  • 算法步骤
    1. 定义x函数,计算每次循环的结果.
    2. 定义slow = n.(第一个数字),定义fast = x(n).(第二个数字),之所以不定义0,是为了可以进得去循环.
    3. 每次slow向后移动一个数字,fast向后移动两个数字.
    4. 直到两个指针相遇,即值相等.
    5. 判断相遇的位置是否等于1.
  • 代码编写
class Solution {public int x(int n){int sum = 0;while (n != 0){sum += (n%10)*(n%10);n/=10;}return sum;}public boolean isHappy(int n) {int slow = n;int fast = x(n);while (slow != fast){slow = x(slow);fast = x(x(fast));}if (slow == 1){return true;}else{return false;}}
}

5. 盛水最多的容器(难度:🟡3度)

OJ链接

  • 题目描述

给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。
找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。
返回容器可以储存的最大水量。
说明:你不能倾斜容器。
示例 1:
在这里插入图片描述
输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂直线代表输入数组 [1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。
示例 2:
输入:height = [1,1]
输出:1

  • 算法原理
    设两个指针left ,right 分别指向容器的左右两个端点,此时容器的容积:
    v = (right - left) * min( height[right], height[left])容器的左边界为height[left] ,右边界为height[right] .
    为了⽅便叙述,我们假设「左边边界」⼩于「右边边界」。
    如果此时我们固定⼀个边界,改变另⼀个边界,⽔的容积会有如下变化形式:
    容器的宽度⼀定变⼩
    ◦ 由于左边界较⼩,决定了⽔的⾼度。如果改变左边界,新的水面高度不确定,但是⼀定不会超
    过右边的柱子高度,因此容器的容积可能会增大

    如果改变右边界,⽆论右边界移动到哪⾥,新的⽔⾯的⾼度⼀定不会超过左边界,也就是不会
    超过现在的⽔⾯⾼度,但是由于容器的宽度减⼩,因此容器的容积⼀定会变⼩的

    综上,我们只需要改变高度较小的一边即可.
    由此可⻅,左边界和其余边界的组合情况都可以舍去所以我们可以left++跳过这个边界,继续去判断下⼀个左右边界
    当我们不断重复上述过程,每次都可以舍去大量不必要的枚举过程,直到leftright相遇。期间产生的所有的容积里面的最大值,就是最终答案。
  • 代码编写
class Solution {public int maxArea(int[] height) {int left = 0;int right = height.length-1;int max = 0;int v = 0; while (left <= right){v = Math.min(height[left],height[right])*(right-left);max = Math.max(v,max);if (height[left] < height[right]){left += 1;}else{right -= 1;}}return max;}
}

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

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

相关文章

SpringBoot2.0.x旧版集成Swagger UI报错Unable to infer base url...解决办法

一、问题描述 1.1项目背景 SpringBoot2.0.9的旧版项目维护开发&#xff0c;集成Swagger-ui2.9.2无法访问的问题。不用想啊&#xff0c;这种老项目是各种过滤器拦截器的配置&#xff0c;访问不到&#xff0c;肯定是它们在作妖。懂得都懂啊&#xff0c;这里交给大家一个排错的办…

Flutter设计模式全面解析:单例模式

谈到设计模式这个“古老”的话题&#xff0c;大家先别急着划走哈&#xff0c;虽然对它再熟悉不过&#xff0c;几乎是最初开始学习编程到现在伴随着我们整个编程生涯&#xff0c;最早 Java、C 语言实现的各种设计模式到现在还会经常有所接触&#xff0c;面试中也是必问的环节&am…

Adobe Camera Raw 11 for Mac/win:摄影后期处理的革命性飞跃

在数字摄影的世界里&#xff0c;RAW格式以其未压缩的原始数据特性&#xff0c;为摄影师提供了更大的后期处理空间。而Adobe Camera Raw 11&#xff0c;作为这一领域的翘楚&#xff0c;以其卓越的性能和创新的功能&#xff0c;为摄影师们带来了前所未有的创作体验。 Adobe Came…

LeetCode450删除二叉搜索树中的节点

题目描述 给定一个二叉搜索树的根节点 root 和一个值 key&#xff0c;删除二叉搜索树中的 key 对应的节点&#xff0c;并保证二叉搜索树的性质不变。返回二叉搜索树&#xff08;有可能被更新&#xff09;的根节点的引用。一般来说&#xff0c;删除节点可分为两个步骤&#xff1…

Linux环境中部署docker私有仓库Registry与远程访问详细流程

目录 前言 1. 部署Docker Registry 2. 本地测试推送镜像 3. Linux 安装cpolar 4. 配置Docker Registry公网访问地址 5. 公网远程推送Docker Registry 6. 固定Docker Registry公网地址 前言 作者简介&#xff1a; 懒大王敲代码&#xff0c;计算机专业应届生 今天给大家聊…

网络安全知识核心20要点

1、什么是SQL注入攻击 概述 攻击者在 HTTP 请求中注入恶意的 SQL 代码&#xff0c;服务器使用参数构建数据库 SQL 命令时&#xff0c;恶意SQL 被一起构造&#xff0c;并在数据库中执行。 注入方法 用户登录&#xff0c;输入用户名 lianggzone&#xff0c;密码‘ or ‘1’’…

揭秘Python的魔法:装饰器的超能力大揭秘 ‍♂️✨

文章目录 Python进阶之装饰器详解1. 引言装饰器的概念与意义装饰器在Python编程中的作用 2. 背景介绍2.1 函数作为对象2.2 高阶函数 3. 装饰器基础3.1 理解装饰器3.2 装饰器的工作原理 4. 带参数的装饰器4.1 为什么需要带参数4.2 实现带参数的装饰器使用函数包裹装饰器使用类实…

TypeScript-泛型

泛型(Generics) 指在定义接口&#xff0c;函数等类型的时候&#xff0c;不预先指定具体的类型&#xff0c;而在使用的时候再指定类型的一种特性&#xff0c;使用泛型可以复用类型并且让类型更加灵活 泛型接口-interface 语法&#xff1a;在 interface 接口类型的名称后面使用…

web前端的路径和Servlet注解开发

目录 在web前端的两种路径 绝对路径的两种写法 相对路径 相对路径进阶 使用注解开发Servlet 使用注解开发Servlet的注意事项 使用idea创建servlet模板 在web前端的两种路径 绝对路径的两种写法 1.带网络三要素 http://ip地址:端口号/资源路径 2.不带网络三要素 /资源路…

『哈哥赠书 - 53期』-『深入浅出 Spring Boot 3.x』

⭐️ 《深入浅出 Spring Boot 3.x》 ⭐️ 学习Spring Boot的必读之书 在 Java 后端开发领域&#xff0c;功能强大的 Spring 开源框架不仅是首选&#xff0c;也是事实上的标准。但由于 Spring 存在配置烦琐、部署不易、依赖管理困难等问题&#xff0c;因此基于 Spring 的快速开…

告别传统,拥抱未来——上门回收小程序引领变革

随着科技的飞速发展&#xff0c;我们生活的方方面面都在经历着前所未有的变革。在环保和可持续发展的背景下&#xff0c;传统的废品回收方式已经难以满足现代社会的需求。而上门回收小程序的出现&#xff0c;正以其便捷、高效的特点&#xff0c;引领着废品回收行业的变革。 一、…

HCIP-Datacom-ARST自选题库__OSPF单选【80道题】

1.OSPFV2是运行在IPV4网络的IGP&#xff0c;OSPFV3是运行在IPV6网络的ICP&#xff0c;OSPFV3与OSPFv2的报文类型相同&#xff0c;包括Hello报文、DD报文、LSR报文、LSU报文和LSAck报文。关于OSPFv3报文&#xff0c;以下哪个说法是正确的 OSPFv3使用报文头部的认证字段完成报文…

抖音跳转微信卡片制作教程 小白也能搞

实测可以正常跳转&#xff0c;很牛逼&#xff0c;给大家分享一下~ 这是我做出来抖音发出去的效果&#xff0c;大家会制作了可以去卖钱&#xff0c;市场上一个这个卡片都要卖50-200&#xff0c;很不错的&#xff01;&#xff01; https://pan.baidu.com/s/1xPmGAWPcbAp7eXg7Dc…

温故而知新-秒杀项目篇【面试复习】

温故而知新-秒杀项目篇【面试复习】 前言版权推荐温故而知新-论坛项目篇【面试】秒杀项目中注册模块怎么实现的&#xff1f;秒杀项目中登录模块怎么实现的&#xff1f;秒杀项目中显示登录用户信息怎么实现的&#xff1f;SessionStorage是什么?为什么不用session而用token什么是…

骨位深间距小模具镶件如何走水路?3D打印让一切简单

在模具制造领域&#xff0c;骨位深且间距小的模具镶件由于结构复杂&#xff0c;传统加工方法难以制造出符合要求的冷却水路&#xff0c;导致模具在注塑过程中容易产生热量积聚&#xff0c;进而引发烫伤、缩孔等不良。然而&#xff0c;随着3D打印技术的飞速发展&#xff0c;这些…

0基础学习Mybatis系列数据库操作框架——Mysql的Geometry数据处理之WKT方案

大纲 几何结构构建点点集合线线集合面面集合几何信息集合 TypeHandlerSQL操作写入操作读取操作完整XML Mapper测试代码建表SQL总结代码参考资料 WKT全称是Well-Known Text。它是一种表达几何信息的字符串内容。比如点可以用WKT表示为POINT (3 3)&#xff1b;线可以用WKT表示为L…

Playwright教程

Playwright简介 支持多数浏览器 在Chromium&#xff0c;Firefox和WebKit上进行测试。Playwright拥有适用于所有现代浏览器的完整API覆盖&#xff0c;包括Google Chrome和Microsoft Edge&#xff08;带有Chromium&#xff09;&#xff0c;Apple Safari&#xff08;带有WebKit&a…

【哈希映射 字符串 乘法原理】2227. 加密解密字符串

本文涉及知识点 哈希映射 字符串 乘法原理 LeetCode 2227. 加密解密字符串 给你一个字符数组 keys &#xff0c;由若干 互不相同 的字符组成。还有一个字符串数组 values &#xff0c;内含若干长度为 2 的字符串。另给你一个字符串数组 dictionary &#xff0c;包含解密后所…

SpringCloud微服务03-微服务保护-分布式事务-MQ基础-MQ高级

一、微服务保护 1.雪崩问题 如何做好后备方案就是后续&#xff1a; 2.雪崩解决方案 某一个服务的线程是固定的&#xff0c;出现故障线程占满后&#xff0c;就不会让取调用这个服务&#xff0c;对其他服务就没有影响。 3.Sentinel ①初识Sentinel 配置过程&#xff1a;day05-服…

C++之多态详解

1. 多态的概念 1.1 概念 多态的概念&#xff1a;通俗来说&#xff0c;就是多种形态&#xff0c;具体点就是去完成某个行为&#xff0c;当不同的对象去完成时会 产生出不同的状态。 举个栗子&#xff1a;比如买票这个行为&#xff0c;当普通人买票时&#xff0c;是全价买票&a…