算法从零到精通 (一) ~ 快慢双指针

1. 前言

快慢双指针是一种常用的算法技巧,通常用于解决涉及链表或数组的问题。它的基本思想是使用两个指针,一个移动速度快(快指针),一个移动速度慢(慢指针),来解决特定的问题。这两个指针通常从序列的起始位置开始,并以不同的步伐向前移动,直到达到特定的条件为止。

  • 快慢双指针是指在算法处理过程中,使用两个指针,分别从序列的起始位置出发,按照不同的步伐向前移动,直到满足某种条件。通常快指针的移动速度比慢指针快,这样可以加快算法的执行速度。
  • 判断链表是否有环:快指针每次移动两步,慢指针每次移动一步,如果存在环,快指针最终会追上慢指针。

  • 找到链表的中间节点:快指针每次移动两步,慢指针每次移动一步,当快指针到达链表末尾时,慢指针所在位置即为中间节点。

  • 移除排序数组中的重复项:使用快慢指针,当快指针遇到不同的元素时,将其复制到慢指针位置,然后慢指针前进一步。

 2. 我对快慢指针的理解

1. 数组划分

  1. cur:从左到右扫描数组,遍历数组(快指针)
  2. dest:已处理的区间内,非零元素的最后一个位置
  3. cur(快指针)遇到符合题意的值,把他加入这个区间。一般是先dest++然后和cur交换

如何做到维护该区间一直到结束,是解题的关键。

// 符合题意           不符合题意            未处理元素
// [0~dest]        [dest + 1 ~ cur]       [cur + 1 ~ n]

达到最终的目的就是持续这三块区域的关系

2. 判断是否成环

快指针每次移动两步,慢指针每次移动一步,如果存在环,快指针最终会追上慢指针。

3 例题分析

3.1 移动零 (数组划分)

 

public void moveZeroes(int[] nums) {// 符合题意(非0元素)    不符合题意(0)    未处理元素// [0~dest]        [dest + 1 ~ cur]       [cur + 1 ~ n]// 要想维护上面的关系到结束,必须让cur遇到符合题意的和dest后一个元素(不符合题意的交换),//                        然后让dest++(扩大符合题意的范围),继续维护该区间int n = nums.length, cur = 0, dest = -1;while(cur != n){if (nums[cur] != 0){//遇到符合题意的,交换来维持三个区间关系dest++;int temp = nums[dest];nums[dest] = nums[cur];nums[cur] = temp;}cur++;}}

3.2 去重

下面的图,就是我对上题一步步的分析:

只要一直维持这三个区域到结束,就可以解答本题。

如何维持,就成了解答本题的关键。

    /*** 思路分析:* 1. dest(慢指针):确定没有重复元素的最后一个位置, cur(快指针):扫描完的最后一个位置* 2. 通过比较快慢指针的内容确定是否重复 (因为非严格递增,相同的都是连续的)* 3. 遇到一个不重复元素,就是符合[0 ~ dest]区间,就和dest+1不符合该区间的交换位置** @param arr* @return*/public static int[] arrayDeduplication(int[] arr) {//默认第一个元素不重复int n = arr.length, dest = 0, cur = 1;while (cur < n) {if (arr[cur] != arr[dest]) {//找到一个不符合题意的dest++;int temp = arr[dest];arr[dest] = arr[cur];arr[cur] = temp;}cur++;}return Arrays.copyOf(arr,dest + 1);}public static void main(String[] args) {int[] arr = {1, 1, 4, 4, 5, 6, 7, 7, 8, 8, 8, 8, 8};int[] distinction = arrayDeduplication(arr);System.out.println(Arrays.toString(distinction));System.out.println(Arrays.toString(arr));}

3.3 复写零

思路分析:

因为正序会造成覆盖,比如 0 1 2  正序读0索引->会变成 0 0 1,下次读1索引就被覆盖了。 

  1. 先判断要舍弃的元素。(因为要复写,数组大小不变总要舍去)
  2. 从后往前复写,0写两次,其余写一次
  3. 判断临界情况,防止最后一个为0且数组长度不够

剩下的内容代码有详细的注释。 

  // 正着写会被覆盖,因此倒序,倒序要确定复写舍弃的元素(复写位置),最后处理临界:cur越界// 1. 通过 0 cur移动两步 和 非0 cur移动一步,确定从dest位置开始复写// 2. 倒序开始写,dest读取到0复写 cur写两遍  非0  cur写一遍// 3. 处理临界:最后一个修改成0, dest-2  cur-1public static void duplicateZeros(int[] arr) {//因为读完写,所以dest(慢指针)为0,cur为-1int n = arr.length, dest = 0, cur = -1;//1.确定dest位置while(dest < n){if (arr[dest] == 0){//写两边cur++;cur++;}else {//写一遍cur++;}if (cur >= n - 1) break;//写到最后或者写过(最后一个为0),dest就不需要读了dest++;}//3. 处理临界if (cur == n){arr[n - 1] = 0;cur--;cur--;dest--;}//此时dest后面就是舍弃的元素//2. 倒序复写while(dest >= 0){if (arr[dest] == 0){//写两边arr[cur--] = 0;arr[cur--] = 0;}else {//写一遍arr[cur--] = arr[dest];}dest--;}}

 

3.4 快乐数(判断环)

 通过数字的取平方和来模拟移动,取一次移动一步,俩次移动两步,这样就可以模拟链表。和判断链表是否有环,原理一样,仅需判断链表中元素是否为1即可。

为什么是必定有环的呢???

原因就是鸽巢原理,所以数据范围有限的情况下,必定有环。5个人有6个糖,必定有一个人是有两个糖即以上的。

public class Test3 {//通过数来模拟指针移动,和判断链表是否有环,原理一样//仅需判断链表中元素是否为1即可//要么是1,要么无限循环的原因就是鸽巢原理,所以数据范围有限的情况下,必定有环public boolean isHappy(int n) {int slow = n, fast = bitSum(n);while(slow != fast){slow = bitSum(slow);fast = bitSum(bitSum(fast));}return slow == 1;}//求一个数各个元素的平方和,相当于移动一次private int bitSum(int num){int sum = 0;while(num != 0){int t = num % 10;sum += t * t;num /= 10;}return sum;}
}

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

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

相关文章

计算机软考之计算机网络知识详解

目录 计算机网络概述计算机网络体系结构 OSI参考模型TCP/IP模型 物理层 传输介质信号传输 数据链路层 数据帧错误检测与纠正 网络层 IP协议路由协议 传输层 TCP协议UDP协议 应用层 常见应用层协议 网络安全 常见安全威胁安全措施 实战案例分析总结 计算机网络概述 计算机网络…

Docker搭建群晖

Docker搭建群晖 本博客介绍在docker下搭建群晖 1.编辑docker-compose.yml文件 version: "3" services:dsm:container_name: dsmimage: vdsm/virtual-dsm:latestenvironment:DISK_SIZE: "16G"cap_add:- NET_ADMIN ports:- 8080:50…

在未来有可能实现无药无手术可以治病吗?

在未来&#xff0c;随着科技的不断进步和人类对健康的追求&#xff0c;无药无手术治病的可能性是存在的。虽然目前的技术水平和医疗手段还无法完全实现这一目标&#xff0c;但是我们可以从多个方面推论出未来可能出现的无药无手术治病的情景。 首先&#xff0c;随着生物科技的发…

基于NER、触发词与依存句法分析的言论抽取

言论抽取技术简介 言论抽取&#xff08;Opinion Mining&#xff09;&#xff0c;是自然语言处理&#xff08;NLP&#xff09;领域中的一个重要分支&#xff0c;主要用于从文本中自动提取和分析情感信息。随着社交媒体、电子商务和在线评论的兴起&#xff0c;言论抽取技术变得越…

红狮金业解读:分析高价位黄金的后续投资吸引力

在全球经济格局不断变化的背景下&#xff0c;黄金作为传统的避险资产一直备受投资者关注。近期&#xff0c;金价持续走高&#xff0c;引发了市场对黄金是否仍然是优质资产配置的讨论。本文红狮启富将从长期需求、价格驱动因素的变化以及汇率影响三个角度&#xff0c;深入分析黄…

开发语言的基本构成。

许多人都对设计一套自有知识产权的开发语言感兴趣。那么&#xff0c;如何按照功能模块设计开发语言&#xff1f; 开发语言必须提供以下基本功能&#xff1a; 数据存储组织和管理&#xff1b;数据定位和访问&#xff1b;数据定义和解释方案&#xff1b;通用算法包&#xff1b;迭…

关于线性代数(考研)

1.AE的特征值的问题 若λ是A的特征值&#xff0c;对应的特征向量是x&#xff0c;则Axλx&#xff0c;所以(AE)xAxExλxx(λ1)x&#xff0c;所以λ1是AE的特征值。所以若A的特征值是1&#xff0c;1&#xff0c;0&#xff0c;则AE的特征值就是11&#xff0c;11&#xff0c;01&am…

c# 端口监控 Helper 以及写一个端口监控工具

c# 端口监控 Helper 以及写一个端口监控工具 介绍核心代码&#xff1a;工具完整编码&#xff1a;1、编写界面2、打开定时控件的属性设置。3、编写定时控件的 Tick 事件结果&#xff08;运行效果&#xff09; 介绍 由于最近做上架比较多&#xff0c;会经常来确保服务器的服务&a…

VUE 子组件可以直接改变父组件的数据吗

子组件不可以直接改变父组件的数据。‌在Vue中&#xff0c;‌数据流是单向的&#xff0c;‌即父组件通过props向子组件传递数据&#xff0c;‌而子组件不能直接修改父组件的数据。‌这是为了维护数据流动的单向性和数据的可维护性。‌ 如果子组件需要修改父组件的数据&#xf…

Flink时间和窗口

目录 时间语义 水位线&#xff08;Watermarks&#xff09; 并行流中的水位线 窗口 滚动窗口—Tumbling Windows 滑动窗口—Sliding Windows 会话窗口—Session Windows 全局窗口—Global Windows 例子 时间语义 如图所示&#xff0c;由事件生成器&#xff08;Event Pr…

萤石举办2024夏季新品发布会,全力推进“2+5+N”智能家居新生态

7月24日&#xff0c;“智动新生&#xff0c;尽在掌控”2024萤石夏季新品发布会在杭州成功举办。本次发布会上&#xff0c;“智慧生活守护者”萤石深入挖掘应用场景&#xff0c;重磅发布了包括智能健康手表、智能家居AI主机、生态控制器、智家APP等多款创新性的产品及应用&#…

【JavaScript】`Map` 数据结构

文章目录 一、Map 的基本概念二、常见操作三、与对象的对比四、实际应用场景 在现代 JavaScript 中&#xff0c;Map 是一种非常重要且强大的数据结构。与传统的对象&#xff08;Object&#xff09;不同&#xff0c;Map 允许您使用各种类型的值作为键&#xff0c;不限于字符串或…

mysql 如何实现重复数据取创建时间的最后一条记录?

重复数据去重&#xff0c;取创建时间最晚的一条。 思路&#xff1a;按重复的字段通过group by 去重&#xff0c;重复的数据通过GROUP_CONCAT(&#xff09;函数收集&#xff0c;再通过SUBSTRING_INDEX(&#xff09;函数截取即可。 实例&#xff1a; SELECTUserName,//字段值按…

基于 HTML+ECharts 实现监控平台数据可视化大屏(含源码)

构建监控平台数据可视化大屏&#xff1a;基于 HTML 和 ECharts 的实现 监控平台的数据可视化对于实时掌握系统状态、快速响应问题至关重要。通过直观的数据展示&#xff0c;运维团队可以迅速发现异常&#xff0c;优化资源配置。本文将详细介绍如何利用 HTML 和 ECharts 实现一个…

关于 夜莺n9e 的简易部署

一、部署夜莺n9e 1.找一个服务器机器 #创建并进入目录 mkdir -p /data/n9e && cd /data/n9e2.准备n9e安装包 (如果存在&#xff0c;跳过) #下载并解压n9e wget https://download.flashcat.cloud/n9e-v6.7.3-linux-amd64.tar.gz tar -zxvf n9e-v6.7.3-linux-amd64.ta…

SecureCRT连接Linux时乱码问题

使用SecureCRT输入中文出现乱码的问题&#xff0c;通常与字符编码和终端的显示设置有关. 发生乱码的原因主要是有三个地方 1.Linux的etc的系统默认配置的编码 2.用户环境变量里面设置的LANG变量 3.SecureCRT会话变量里面的字符集的设置 只要保持这三个地方的字条集编码保持一致…

学习笔记7:gitlab ci/cd

gitlab ci/cd GitLab CI/CD 是 GitLab 提供的持续集成和持续部署工具。它是一种自动化的流程&#xff0c;用于在软件开发过程中自动构建、测试和部署应用程序。以下是 GitLab CI/CD 的一些关键特性和概念&#xff1a; 持续集成&#xff08;Continuous Integration, CI&#xf…

JL 跳转指令的理解

一般情况下&#xff0c;JU 和 JC 是最常见的跳转指令&#xff1b;但有时会用到JL 指令&#xff0c;JL 说起来更像是一组指令&#xff0c;类似C,C# 语言中的 switch case 语句&#xff0c;但是有个明显的不同&#xff0c;前者的判断条件可以是任意合理数字&#xff0c;后者范围…

制冷系统干燥过滤器

干燥过滤器(Drier Filter)主要是起到杂质过滤的作用。一般来说&#xff0c;这要根据冰箱、空调的制冷系统来确定干燥器的规格&#xff0c;如直径&#xff0c;内径&#xff0c;外径的规格&#xff0c;和内部件&#xff0c;如过滤碗&#xff0c;网布&#xff0c;和分子筛 为了确保…

C#测试控制台程序调用Quartz.NET的基本用法

Quartz.Net是常用的任务调用框架之一&#xff0c;既能在客户端程序中使用&#xff0c;也支持在网页程序后台调用。本文结合参考文献4中的示例代码学习其在控制台程序中的基本用法。   VS2022新建控制台项目&#xff0c;在Nuget包管理器中搜索并安装Quartz包&#xff0c;如下所…