Pattern: Fast & Slow pointers, 快慢指针类型

介绍部分来自:链接:https://www.zhihu.com/question/36738189/answer/908664455 作者:穷码农

这种模式,有一个非常出门的名字,叫龟兔赛跑。 咱们肯定都知道龟兔赛跑啦。但还是再解释一下快慢指针:这种算法的两个指针的在数组上(或是链表上,序列上)的移动速度不一样。还别说,这种方法在解决有环的链表和数组时特别有用

通过控制指针不同的移动速度(比如在环形链表上),这种算法证明了他们肯定会相遇的。快的一个指针肯定会追上慢的一个(可以想象成跑道上面跑得快的人套圈跑得慢的人)。

​ 上面这个图演示了快慢两个指针最终在5相遇了

咋知道需要用快慢指针模式勒?

  • 问题需要处理环上的问题,比如环形链表和环形数组
  • 当你需要知道链表的长度或是某个特别位置的信息的时候

那啥时候用快慢指针而不是上面的双指针呢?

  • 有些情形下,咱们不应该用双指针,比如我们在单链表上不能往回移动的时候。一个典型的需要用到快慢指针的模式的是当你需要去判断一个链表是否是回文的时候。

总结: 慢指针执行一个步骤,快指针执行另两个步骤。快慢指针一般用于两者最终可以相遇(相等)的情况下使用。

经典题目:

链表的数据结构:

// Definition for singly-linked list.
class ListNode {int val;ListNode next;ListNode(int x) {val = x;next = null;}
}

1、LinkedList Cycle (easy)

141. 环形链表

102. 带环链表

描述:

​ 给定一个链表,判断链表中是否有环。

​ 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。注意:pos 不作为参数进行传递,仅仅是为了标识链表的实际情况。

​ 如果链表中存在环,则返回 true 。 否则,返回 false 。

​ 进阶:

​ 你能用 O(1)(即,常量)内存解决此问题吗?

示例:

示例 1:

​    输入:head = [3,2,0,-4], pos = 1
​   输出:true
​   解释:链表中有一个环,其尾部连接到第二个节点。

示例 2:

​    输入:head = [1,2], pos = 0
​   输出:true
​   解释:链表中有一个环,其尾部连接到第一个节点。

示例 3:

​    输入:head = [1], pos = -1
​   输出:false
​   解释:链表中没有环。

使用快慢指针:

public boolean hasCycle(ListNode head) {if (head == null)return false;ListNode slow = head;        // 慢指针ListNode fast = head;        // 快指针while (fast != null && fast.next != null){fast = fast.next.next;   // 快指针走两步slow = slow.next;        // 慢指针走一步if (fast == slow)        // 最终相遇则有环return true;}return false;
}

使用破坏链表法:

public boolean hasCycle(ListNode head) {if (head == null)return false;ListNode p = head;while (p != null){ListNode next = p.next;             // 下一个节点if (next == head) return true;      // 等于头节点则返回p.next = head;                      // 破坏链表p = next;                           // 下一个节点继续遍历}return false;
}

2、Start of LinkedList Cycle (medium)

注意: 慢指针一定是走不到一圈就相遇了,因为如果在环的入口点没有相遇的话,快指针的速度是慢指针的两倍,慢指针在入口点时快指针已经进入环内,在慢指针走完一圈之前,快指针一定会追上它。最差的情况就是在入口点相遇,这是快指针走了两圈,慢指针刚好走了一圈。

​ 快指针每次走两步:a + nc + b

​ 慢指针每次走一步:a + b

​ 距离关系有 a + nc + b = 2(a + b) 得:a = b - nc

​ 当 n = 1a = c - b 。也就是 相遇点到环起点(顺时针) = 起始点到环起点故使用一个指针从头结点开始遍历,慢指针从相遇点开始遍历,两者就会在环起点相遇。

​ 当 n = 0时,a = b也就是表头就是环入口点。

public class Solution {public ListNode detectCycle(ListNode head) {if (head == null)return null;// 找出相遇点ListNode slow = head;       // 慢指针,每次走一步ListNode fast = head;       // 快指针,每次走两步boolean isCycle = false;    // 是否有环标志while (fast != null && fast.next != null){fast = fast.next.next;   // 走两步slow = slow.next;        // 走一步if (fast == slow){isCycle = true;     // 有环标志break;              // 退出循环}}// 有环则找出起始点if (isCycle){ListNode first = head;      // 从头结点开始遍历,最终和慢指针在环入口点相遇while (first != slow){first = first.next;slow = slow.next;}return slow;}else {return null;}}
}

3、Happy Number (medium)

202. 快乐数

488. 快乐数关注问题

描述

​ 写一个算法来判断一个数是不是"快乐数"。

​ 一个数是不是快乐是这么定义的:对于一个正整数,每一次将该数替换为他每个位置上的数字的平方和,然后重复这个过程直到这个数变为1,或是无限循环但始 终变不到1。如果可以变为1,那么这个数就是快乐数。

样例

例1:

输入:19
输出:true
说明:
19是一个快乐的数字1 ^ 2 + 9 ^ 2 = 828 ^ 2 + 2 ^ 2 = 686 ^ 2 + 8 ^ 2 = 1001 ^ 2 + 0 ^ 2 + 0 ^ 2 = 1

例2:

输入:5
输出:false
说明:
5不是一个快乐的数字
25->29->85->89->145->42->20->4->16->37->58->89
再次出现89。

如果给定的数字会一直循环,则可以使用快慢指针判断是否重复。

slow 指针进行一次替换操作

fast 指针进行两次替换操作

他们最终会在重复的数字相遇,即slow==fast

如果他们最终都为 slow == fast == 1,即快乐数。否则,为不快乐数。

class Solution {public boolean isHappy(int n) {if (n == 0)return false;if (n == 1)return true;int slow = n;       // 慢指针,进行一次替换操作int fast = n;       // 快指针,进行两次替换操作// 当 slow != fast 时一直循环do {slow = squareSum(slow);fast = squareSum(fast);fast = squareSum(fast);}while (slow != fast);// 在 1 相遇 即 slow == fast == 1 即快乐数if (fast == 1){return true;}return false;}public int squareSum(int n){int squareSum = 0;while (n != 0){squareSum += (n % 10) * (n % 10);       // 取个位数n /= 10;                                // 缩小十位}return squareSum;}
}

4、Middle of the LinkedList (easy)

876. 链表的中间结点

1609. 链表的中间结点

描述

​ 给定一个带有头结点 head 的非空单链表,返回链表的中间结点。

​ 如果有两个中间结点,则返回第二个中间结点。

​ The number of nodes in the given list will be between 1 and 100.

样例

样例 1:

输入:1->2->3->4->5->null
输出:3->4->5->null

样例 2:

输入:1->2->3->4->5->6->null
输出:4->5->6->null

解题思路:

使用快慢指针,快指针每次走两步,慢指针每次走一步。当快指针到达链表尾部的时候,慢指针就到达链表的中部。

public class Solution {/*** @param head: the head node* @return: the middle node*/public ListNode middleNode(ListNode head) {// write your code here.if (head == null)return null;ListNode slow = head;       // 慢指针,每次走一步ListNode fast = head;       // 快指针,每次走两步while (fast != null && fast.next != null){slow = slow.next;fast = fast.next.next;}return slow;}
}

快慢指针类型(Fast Slow pointers)相关推荐

  1. 试编写一个将双向循环链表逆置的算法_图解:链表的快慢指针,解决 80% 的链表面试题!...

    一.前言 链表是基本的数据结构之一,它与数组不同,数组在内存中存储,需要一块连续的内容空间来存储,对内存的要求比较高.例如我们需要 100MB 大小的数组,内存中就必须有一段连续的 100MB 的内存 ...

  2. 面试题 02.08. 环路检测-快慢指针+如何找到环的入口?(证明)Java

    1.题目 2.思路 方法一--哈希表记录节点 思路很简单,记录一下每个节点出现的次数,如果某个节点出现了两次,代表此时有环,并且是环的入口,直接返回即可. 时间复杂度O(N) 空间复杂度O(N) pu ...

  3. [Leedcode][JAVA][第876题][快慢指针]

    [问题描述] 给定一个带有头结点 head 的非空单链表,返回链表的中间结点. 如果有两个中间结点,则返回第二个中间结点. 示例 1: 输入:[1,2,3,4,5] 输出:此列表中的结点 3 (序列化 ...

  4. 链表的中间节点--快慢指针

    问题来源:链表的中间节点 问题描述:给定一个带有头结点 head 的非空单链表,返回链表的中间结点.如果有两个中间结点,则返回第二个中间结点. 例子: 输入:[1,2,3,4,5] 输出:此列表中的结 ...

  5. 数组双指针之快慢指针

    数组双指针 数组双指针分为两类: 左右双指针:左指针在最左侧,右指针在最右侧,它们相向而行 快慢双指针:在单链表中经常使用fast.slow指针去判断链表中是否成环.单链表的终点.单链表倒数第k个结点 ...

  6. 双指针--快慢指针和对撞指针

    1.基础概念 两个指针有 n*n种组合,因此时间复杂度是 O(n^2) .而双指针算法就是运用单调性使得指针只能单向移动,因此总的时间复杂度只有 O(2n),也就是O(n).双指针可以分为两种类型,一 ...

  7. 详细总结快慢指针的在链表中的常见题型

    常见快慢指针题型 1.找出链表中间结点 2.找到倒数第K个结点 3.判断环形链表 4.找到环形链表的入口(进阶) 5.相交链表 1.找出链表中间结点 双指针进阶解法 1.定义两个指针,一个快指针,一个 ...

  8. LeetCode 例题精讲 | 05 双指针×链表问题:快慢指针

    点击关注上方"五分钟学算法", 设为"置顶或星标",第一时间送达干货. 转自面向大象编程 本期例题: LeetCode 876 - Middle of the ...

  9. reorder-list——链表、快慢指针、逆转链表、链表合并

    Given a singly linked list L: L0→L1→-→Ln-1→Ln, reorder it to: L0→Ln→L1→Ln-1→L2→Ln-2→- You must do th ...

最新文章

  1. js修改地址栏url_在gulp、create-react-app中css,js中的文件路径
  2. 快准牌电脑发软件_电脑如何下载软件
  3. 教徒计划出品:升级ESXI41-ESXI5
  4. Visual Studio容器项目工程化心得
  5. 使用sikuli和Arquillian测试HTML5 canvas应用程序
  6. C语言自加自减运算符(++i / i++) - C语言零基础入门教程
  7. 2020笔记本性价比之王_什么笔记本性价比高?2020性价比最高的笔记本电脑
  8. Civil 3D 二次开发 新建CLR项目出现错误C2143
  9. 数据结构:列表(双向链表)的了解与示例
  10. 基础笔记8(二)(容器-引用类型的排序)
  11. 如何提升大数据分析能力
  12. python 下载bilibili视频
  13. 中石油职称计算机试题,中石油职称计算机水平考试复习题库22-职称计算机考试其它试卷与试题.pdf...
  14. Manjaro Gnome 安装TIM
  15. 2022-2028中国安全代码审查软件市场现状研究分析与发展前景预测报告
  16. UML (统一建模语言) 各种图总结
  17. 基础电路设计知识:电阻、电容、电感、二极管、三极管、mos管!
  18. 2021年中国商业银行企业避险业务分析:引导企业坚持汇率风险中性理念[图]
  19. 新增免费根据商品条码查询商品名称API
  20. html实现360展示图片,js html5 360度全景图片预览效果

热门文章

  1. WPS插入图片,结果图片竟然之出现一半的解决方法
  2. 登录(记住账号密码、获取后台数据)
  3. 机器学习环境配置踩坑总结
  4. vcs+verdi仿真Verilog代码
  5. python删库_python常用删除库的方法
  6. 论文阅读笔记:BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding
  7. 手机电池的保护电路详细介绍
  8. vue详解--- es5和es6的基本语法
  9. Easy poi导出科学计数法问题
  10. 门禁服务器故障怎样修复,门禁系统出故障的几种解决方法