两个双指针 的 “他“和“ 她“会相遇么? —— “双指针“算法 (Java版)

本篇会加入个人的所谓鱼式疯言

❤️❤️❤️鱼式疯言:❤️❤️❤️此疯言非彼疯言
而是理解过并总结出来通俗易懂的大白话,
小编会尽可能的在每个概念后插入鱼式疯言,帮助大家理解的.
🤭🤭🤭可能说的不是那么严谨.但小编初心是能让更多人能接受我们这个概念 !!!

在这里插入图片描述

前言

因为小编最近在学习算法, 每次学习新知识,都会有新的体会和心得,就会和小伙伴们一起分享, 今天 带来我们 算法 首篇 ————“双指针” 算法 💥💥💥

这时就会有小伙伴问了,我们的"双指针"算法 不是在 “题海寻offer” 专题中讲解过么 ? 为啥还要重复学习呢 🤔 🤔 🤔

是的, 但这次小编带来的是更重点更详细并且更系统以算法的角度一步一步讲解我们的 “双指针” 算法 💖 💖 💖

目录

  1. 双指针算法初识

  2. 双指针算法的运用

  3. 双指针算法的总结

一. 双指针初识

1. 双指针算法的认识

首先小编在这里得区别一个概念

这里我们提及的 双“指针” 的指针 并不是我们学过 C语言 的 定义 int * p = &a 那个指针 ,

这里我们用的指针其实就是一个 变量

我们通过 变量 来指向一个元素 然后不断移动来影响数据的一个单纯的 变量

双指针 就是定义两个变量来 影响数据

2. 双指针算法的种类

常见的双指针有两种形式:

一种是 对撞指针,一种是 左右指针

对撞指针

对撞指针 从两端向中间移动。一个指针从 最左端 开始,另一个从 最右端 开始,然后逐渐往 中间 逼近。

对撞指针 的终止条件一般是两个指针 相遇=或者 错开(也可能在循环内部找到结果直接跳出循环),也就是:

left == right (两个指针指向同一个位置)

left > right (两个指针错开)

快慢指针

快慢指针:又称为 龟兔赛跑算法,其基本思想就是使用两个移动 速度不同 的指针在数组或链表等序列结构上移动。

这种方法对于处理 环形链表数组 非常有用。

其实不单单是环形链表或者是数组,如果我们要研究的问题出现 循环往复 的情况时,均可考虑使用 快慢指针 的思想。

快慢指针的实现方式有很多种,最常用的一种就是:

在一次循环中,每次让慢的指针向后移动 一位 ,而快的指针往后移动 两位,实现一快一慢

鱼式疯言

总结三句话

  1. 指针本质上是 变量, 只是形式上我们俗称 “指针”

  2. 对撞指针 是 从起点和终点两个 同时 相向 走,会相遇 的两个指针

  3. 快慢指针 是 同向不相遇的两个走的跨度不一样的指针

二. 双指针的算法运用

1. 复写零

1089.复写零题目链接

<1> . 题目描述

在这里插入图片描述

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

题目的 含义

在这个数组中,我们 从左往右 ,每出现一个0 就在右边位置再 写一个 0 ,然后数据一直 挪动 , 原有数据就要一直往右 挪动

<2>. 讲解算法原理

大体思路 分为 :

如果 「从前向后」 进行原地复写操作的话,由于 0 的出现会 复写两次 ,导致没有复写的数 「被覆
盖掉」
。因此我们选择 「从后往前」 的复写策略。

但是 「从后向前」 复写的时候,我们需要找到 `「最后一个复写的数」 `` ,因此我们的大体流程分两
步:

算法流程

  • 先找到最后一个复写的数

请添加图片描述

  1. 先定义一个 cur=0dest= -1 指针来 通向移动
  1. 先让 cur 向前走一步 , 当 cur 位置遇到 值 为 0 时就 dest 就走 两 步

3,否则让 dest 走一步 ,直到 dest 到底 数组下标 >= n- 1 的位置就停止

  • 然后从后向前进行复写操作。

请添加图片描述

  1. cur 遇到 0 时 ,就让 dest 跳跃两次 并 把这两次的值都赋值为 0cur 走一步
  1. cur 不是 0 时 ,就把 cur 的值赋给 dest , 接着让 dest 和 cur 都走一步

<3>. 编写代码

class Solution {public static void duplicateZeros(int[] arr) {int cur=0;int dest=-1;int n=arr.length;while (cur < n) {if (arr[cur]==0) {dest +=2;} else {dest++;}if (dest >= n-1) {break;}cur++;}if (dest > n-1) {arr[n-1]=0;cur--;dest-=2;}while (cur >= 0) {if (arr[cur]==0) {arr[dest--]=0;arr[dest--]=0;cur--;} else {arr[dest--]=arr[cur--];}}}}

在这里插入图片描述

鱼式疯言

说两句小编关于本题自己的理解和体会

  1. 这里我们用到了 前后指针(快慢指针) , 一个 快指针 模拟 复写零 后的数组的位置 , 而 慢指针 用于 模拟 == 未复写零后的数组的最后一个元素的位置
  1. 细节
   if (dest > n-1) {arr[n-1]=0;cur--;dest-=2;}

当 == dest== 的位置跳到 n 的位置时, 说明 0 的位置不够放 , 我们就需要 把最后一个位置 赋值为 0
并让 dest 想左走两步, cur 走一步即可

2. 快乐数

202. 快乐数题目链接

<1>. 题目描述

在这里插入图片描述

编写一个算法来判断一个数 n 是不是快乐数。

「快乐数」 定义为:

◦ 对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和。

◦ 然后重复这个过程直到这个数变为 1,也可能是无限循环但始终变不到 1 。

◦ 如果这个过程 结果为 1 ,那么这个数就是快乐数。

◦ 如果 n 是 快乐数 就返回 true ;不是,则返回 false 。

示例 1:
输入: n = 19
输出: true
解释:
19 -> 1 * 1 + 9 * 9 = 82
82 -> 8 * 8 + 2 * 2 = 68
68 -> 6 * 6 + 8 * 8 = 100
100 -> 1 * 1 + 0 * 0 + 0 * 0 = 1

示例 2:
输入: n = 2
输出: false
解释:(这里省去计算过程,只列出转换后的数)
2 -> 4 -> 16 -> 37 -> 58 -> 89 -> 145 -> 42 -> 20 -> 4 -> 16

往后就不必再计算了,因为出现了重复的数字,最后结果肯定不会是1

题目含义:

让一个数一直取出每个位置上的数字的 平方算出他们的之和 ,得到这个数后 判断是否为 1

如果为 1 说明是快乐数 返回 true

如果继续循环的按照上面的方法计算知道 得到看是否 最终结果为 1= ,若不是就返回 false

<2>. 讲解算法思想

我们先简单的分析一下

为了方便叙述,将「对于一个正整数,每一次将该数替换为它每个位置上的数字的平方和」这一个
操作记为 x 操作;

题目告诉我们,当我们不断重复 x 操作的时候,计算一定会 「死循环」 ,死的方式有 两种

▪ 情况一:一直在 1死循环 ,即 1 -> 1 -> 1 -> 1…

请添加图片描述

▪ 情况二:在历史的数据中死循环,但始终变不到 1

请添加图片描述

由于上述两种情况只会出现一种

因此,只要我们能确定循环是在 「情况一」 中进行

还是在 「情况二 ] 中进行,就能得到结果。

大体的算法思想

先用一个方法来 获取到每一位上数字的 平方之和

由于我们在循环内查找这个数 (相当于检查一个链表是否成环) , 所以我们第一步考虑的应该是 快慢指针 的思维,

我们进行利用 定义 一个 left 的单位为 1 走一步, 再定义一个 right 单位为 2 走两步 ,因为是环形所以 最终是一定会相遇的

最后一步 我们只需要在相遇的位置判断是否是 等于 1 即可

请添加图片描述

<3>. 编写代码

class Solution {public boolean isHappy(int n) {int slow=n;int fast=happyFunc(n);// 一定会成环的while(slow != fast) {slow = happyFunc(slow);fast = happyFunc(happyFunc(fast));}// 最终相遇时只要为 1 就为快乐数if(slow==1) {return true;}return false;}private int happyFunc(int n) {int sum=0;while(n != 0) {int t = n % 10;sum += (t*t);n /= 10; }return sum;}}

在这里插入图片描述

鱼式疯言

先说几点体会吧

  1. 当我们碰到 一个成环或者循环 的一种结构时, 快慢指针的思路是很有必要去尝试的
  1. 本题 的 特点 最终是会成为一个 特定的值 , 我们只需要循环判断即可
  1. 本题细节
int slow=n;int fast=happyFunc(n);

初始化的时候

不可以让 fast 和 slow 同时为 n ,否则就进入不了 循环 .

3. 查找总价值 为目标值的两个商品

179. 查找总价值为目标值的两个商品题目链接

<1>. 题目描述

在这里插入图片描述

输入一个 递增 排序的数组和一个数字s ,在数组中查找两个数,使得它们的和正好是s 。如果有多
对数字的和等于s ,则输出 任意一对 即可。

示例 1:
输入: nums = [2,7,11,15], target = 9
输出: [2,7] 或者 [7,2]

题目含义 就是找两个和为 s 的数字

<2>. 讲解算法思想

题目分析

如果我们要求两个数的 ,只需要先 固定 一个数,然后再 寻找其他数 判断即可寻找到

暴力枚举

两层 for 循环列出所有两个数字的组合,判断是否等于目标值。

双指针 的思路

当我们看到 一个有序数组的时候, 我们头脑中就得建立两个思路 :

一个 二分查找 算法

一个 双指针 算法

而在本题中更适合用我们的双指针来解决 两数和 的问题

  1. 先定义一个指针为 left = 0 , 另一个指针为 right = n-1
  1. leftright 的 数值之和 > target 时 ,我们就让 较大值 right --

left 和 right 的数组之和 < target 时, 我们就让较小值 left ++ ;

直到最终相遇或者寻找到目标值 target 为止 ,

请添加图片描述

<3>. 编写代码

class Solution {public int[] twoSum(int[] price, int target) {int right=price.length-1;int left=0;int []ret=new int[2];while(left < right) {if(price[left] +price[right] > target) {right--;} else if (price[left] +price[right] < target){left++;} else {ret[0]=price[left];ret[1]=price[right];return ret; }}  return ret; }
}

在这里插入图片描述

鱼式疯言

记住一点

有序就要想到用 二分查找算法 或者 双指针算法

4 有效三角形个数

611.有效三角形个数题目链接

<1>. 题目描述

在这里插入图片描述

给定一个包含非负整数的数组 nums ,返回其中可以组成三角形三条边的三元组个数。

示例 1:

输入: nums = [2,2,3,4]
输出: 3
解释:有效的组合是:
2,3,4 (使用第一个 2)
2,3,4 (使用第二个 2)
2,2,3

示例 2:

输入: nums = [4,2,3,4]
输出: 4

题目含义 :

找出所有能满足 组合 三角形三条边 的个数(包含相同数字的边)

<2>. 讲解算法思想

题目分析

如果我们要找三条边, 先 固定两个数 的基础上

再找另外一个数来判断是否满足 三角形三边条件

算法过程

解法一 : 暴力枚举

三个 for= 来查找 是否存在该数据

解法二 : 双指针算法

先将 数组排序

根据「解法一」中的优化思想,我们可以固定一个「最长边」,然后在比这条边小的有序数组中找
出一个二元组,使这个二元组之和大于这个最长边。由于数组是有序的,我们可以利用「对撞指
针」来优化。

设最长边枚举到 i 位置,区间 [left, right]i 位置**左边的区间(**也就是比它小的区
间):

◦ 如果 nums[left] + nums[right] > nums[i]

▪ 说明 [left, right - 1] 区间上的所有元素均可以与 nums[right] 构成比
nums[i] 大的二元组

▪ 满足条件的有 right - left

▪ 此时 right 位置的元素的所有情况相当于全部考虑完毕, right-- ,进入下一轮判断

◦ 如果 nums[left] + nums[right] <= nums[i]

▪ 说明 left 位置的元素是不可能与 [left + 1, right] 位置上的元素构成满足条件
的二元组

left 位置的元素可以舍去left++ 进入下轮循环

请添加图片描述

<3>. 编写代码

class Solution {public int triangleNumber(int[] nums) {Arrays.sort(nums);int sz = nums.length;int count=0;for(int i=sz-1; i >= 2 ; i--) {int left=0,right=i-1;while(left < right) {if(nums[left] + nums[right] > nums[i]) {count += (right-left);right--;} else {left++;}}}return count;  }
}

在这里插入图片描述

鱼式疯言

讲两点

  1. 必须 先排序 ,利用本身的 单调性 来进行 两个较小值和最大值进行比较来判断

所以我们得出以下结论

有序 》 单调性 》 双指针

三. 双指针算法的总结

复写零快乐数 时, 用到了(快慢指针).特别在快乐数的时候,我们在循环的特点下

我们建立了 快慢指针的思路

而在 查找两个数之和有效三角形个数 时, 我们用到了 双指针(对撞指针)

而在这里我们巧妙的利用 单调性 的方法来建立 对撞指针 的模型

如果觉得小编写的还不错的咱可支持 三连 下 (定有回访哦) , 不妥当的咱请评论区 指正

希望我的文章能给各位宝子们带来哪怕一点点的收获就是 小编创作 的最大 动力 💖 💖 💖

在这里插入图片描述

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

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

相关文章

springboot kafka 提高拉取数量

文章目录 背景问题复现解决问题原理分析fetch.min.bytesfetch.max.wait.ms源码分析ReplicaManager#fetchMessages 背景 开发过程中&#xff0c;使用kafka批量消费&#xff0c;发现拉取数量一直为1&#xff0c;如何提高批量拉取数量&#xff0c;记录下踩坑记录。 问题复现 ka…

攻防对抗少丢分,爱加密帮您筑起第二防线

应用程序通常处理和存储大量的敏感数据&#xff0c;如用户个人信息、财务信息、商业数据、国家数据等&#xff0c;用户量越大的应用程序&#xff0c;其需要存储和保护的用户数据越多。因此应用层长期是攻击方的核心目标&#xff0c;传统应用安全依靠防火墙(FireWall)、入侵检测…

iOS组件化 方案 实现

iOS组件化 组件化的原因现在流行的组件化方案方案一、url-block &#xff08;基于 URL Router&#xff09;方案二、protocol调用方式解读 方案三、target-action调用方式解读 gitHub代码链接参考 组件化的原因 模块间解耦模块重用提高团队协作开发效率单元测试 当项目App处于…

网络原理-四

一、续 当窗口大小为0,意味着缓冲区满了,此时发送方,就因该暂停发送,发送方会周期性的除法 " 窗口探测包 " ,并不携带载荷,这样的包对于业务不产生影响,只是为了触发ACK,一旦查询出来的结果是非0,缓冲区右有空间了,发送方就可以继续发送. 二、拥塞控制 要限制发送方…

【AI+知识库问答】沉浸式体验了解 AI知识库问答fastGPT

之前写过一篇文章 【AI本地知识库】个人整理的几种常见本地知识库技术方案 &#xff0c; 由于当时主要是针对AI本地知识库&#xff0c; 所以没列fastGPT。 最近经常刷到fastGPT&#xff0c;这里单独水一篇。 FastGPT 是一个基于 LLM 大语言模型的知识库问答系统&#xff0c;…

Github 2024-06-01 开源项目日报Top10

根据Github Trendings的统计,今日(2024-06-01统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目5Jupyter Notebook项目2TypeScript项目1Go项目1Shell项目1Lua项目1Kong:云原生API网关与AI能力 创建周期:3482 天开发语言:Lua协议…

云原生架构相关技术_4.服务网格

1.技术特点 服务网格&#xff08;ServiceMesh&#xff09;是分布式应用在微服务软件架构之上发展起来的新技术&#xff0c;旨在将那些微服务间的连接、安全、流量控制和可观测等通用功能下沉为平台基础设施&#xff0c;实现应用与平台基础设施的解耦。这个解耦意味着开发者无需…

Chisel入门——在windows下vscode搭建|部署Scala2.13.3开发环境|用Chisel点亮FPGA小灯等实验

文章目录 前言一、vscode搭建scala开发环境1.1 安装Scala官方插件1.2 创建hello_world.scala文件1.3 确认java的版本(博主使用的是1.8)1.4 下载Scala Windows版本的二进制文件1.5 配置环境变量1.6 交互模式测试一下1.7 vscode运行scala 二、windows安装sbt2.1 下载sbt2.2 设置环…

函数递归及具体例子(持续更新)

递归就是函数自己调用自己 求n的阶乘 n! n * (n - 1)! 直到n为1或者0的时候为止 举个例子 int Fun(int n) {if (n < 0){return 1;}else{return n * Fun(n - 1);} }int main() {int n 0;scanf("%d", &n);int ret Fun(n);printf("%d\n", ret…

安装Kubernetes v3 ----以docker的方式部署

以docker的方式部署 docker run -d \ --restartunless-stopped \ --namekuboard \ -p 80:80/tcp \ -p 10081:10081/tcp \ -e KUBOARD_ENDPOINT"http://192.168.136.55:80" \ -e KUBOARD_AGENT_SERVER_TCP_PORT"10081" \ -v /root/kuboard-data:/data \ e…

springboot中抽象类无法注入到ioc容器

1、背景 在写代码时&#xff0c;发现service接口有两个实现类&#xff0c;并且两个实现类中没有对类名重命名&#xff0c;属性注入的时候也没有使用byName或Qualifier&#xff0c;正确情况下会发生多实现报错的问题&#xff0c;以前对这个问题进行解析过。 2、调试过程 我想…

【设计模式】创建型-建造者模式

前言 在面向对象的软件开发中&#xff0c;构建复杂对象时经常会遇到许多挑战。一种常见的解决方案是使用设计模式&#xff0c;其中建造者模式是一个强大而灵活的选择。本文将深入探讨建造者模式的原理、结构、优点以及如何在实际项目中应用它。 一、复杂的对象 public class…

飞凌嵌入式FET3568/3568J-C核心板现已适配OpenHarmony4.1

近日&#xff0c;飞凌嵌入式为FET3568/3568J-C核心板适配了OpenHarmony4.1系统&#xff0c;新系统的加持使核心板在兼容性、稳定性与安全性等方面都得到进一步提升&#xff0c;不仅为FET3568/3568J-C核心板赋予了更强大的功能&#xff0c;也为开发者们提供了更加广阔的创新空间…

每日一练编程题:今天是【接口,多态】

设计程序 : 电脑类的属性USB接口数组 : 有3个usb插口电脑类的功能 : 通过接口插入外设 (u盘,麦克风,键盘等) addUSB(USB usb) { }开机 要求: 电脑开机前,先启动外设关机 要求: 电脑关机前,先关闭外设 外设类(u盘,麦克风,键盘等) 功能 : 启动 关闭 USB接口 定义usb设备的统一…

python多种方式 保留小数点位数(附Demo)

目录 前言1. 字符串格式2. round函数3. Decimal模块4. numpy库5. Demo 前言 在Python中&#xff0c;保留小数点后特定位数可以通过多种方式实现 以下是几种常见的方法&#xff0c;并附上相应的代码示例&#xff1a; 使用字符串格式化&#xff08;String Formatting&#xff…

Ubuntu20.04 Mysql基本操作知识

#Mysql基本知识 运行环境Ubuntu20.04 1.开启mysql服务 sytemctl start mysql不然&#xff0c;命令行进入myql交互行提交命令后&#xff0c;就会出现4200错误。 2.显示所有数据库 SHOW DATABASES;注意复数s&#xff0c;毕竟很多数据库 3.新建数据库test CREATE DATABASE …

【学习笔记】计算机组成原理(九+十)

控制单元的功能 文章目录 控制单元的功能9.1 微操作命令的分析9.1.1 取指周期9.1.2 间址周期9.1.3 执行周期9.1.4 中断周期 9.2 控制单元的功能9.2.1 控制单元的外特性9.2.2 控制信号举例9.2.3 多级时序系统9.2.4 控制方式 控制单元的设计10.1 组合逻辑设计10.1.1 组合逻辑控制…

LabVIEW与Simulink的通信及调用方式

LabVIEW和Simulink可以通过多种方式进行通信和集成&#xff0c;实现数据交互和功能调用。常见的通信方式包括TCP/IP、UDP、共享内存等&#xff0c;此外还可以利用MATLAB Script Node和S-Function等直接调用对方的功能。这些方法使得LabVIEW和Simulink能够协同工作&#xff0c;充…

[Algorithm][动态规划][子序列问题][最长递增子序列的个数][最长数对链]详细讲解

目录 1.最长递增子序列的个数1.题目链接2.算法原理详解3.代码实现 2.最长数对链1.题目链接2.算法原理详解3.代码实现 1.最长递增子序列的个数 1.题目链接 最长递增子序列的个数 2.算法原理详解 注意&#xff1a;本题思路和思维方式及用到的方法很值得考究&#xff0c;个人感…

dubbo复习:(18)服务端Filter

用来在服务响应返回到客户端之前进行额外处理。 一、定义Filter package cn.edu.tju.config;import org.apache.dubbo.rpc.Filter; import org.apache.dubbo.rpc.Result; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Invocation; import org.apache.du…