zoukankan      html  css  js  c++  java
  • Floyd's cycle-finding algorithm

    Floyd's cycle-finding algorithm

    引用维基百科的定义:Floyd's cycle-finding algorithm is a pointer algorithm that uses only two pointers, which move through the sequence at different speeds. It is also called the "tortoise and the hare algorithm".

    此算法主要应用于链表中,主要是判断链表是否有环以及环的起始位置。

    这两个内容刚好对应于 LeetCode 的两道题,此随笔就以这两道题来讲解一下这个巧妙的算法。下面给出这两道题在 LeetCode 中的链接:

    下面的实例代码都用 JavaScript 实现。

    判断链表是否有环

    此算法的主要思想就是双指针,hare 指针一次两步,tortoise 一次一步,如果链表有环,那么 hare 总会追上 tortoise

    hare 一次三步可以吗,应该是可以的,如果有环,它们总会相遇的。但是可能 hare 就要辛苦些, 绕环跑多几圈。

    /**
     * Definition for singly-linked list.
     * function ListNode(val) {
     *     this.val = val;
     *     this.next = null;
     * }
     */
    
    /**
     * @param {ListNode} head
     * @return {boolean}
     */
    var hasCycle = function(head) {
      if (!head) return false;
        
      let tortoise = head;
      hare = head;
      while (hare && hare.next) {
        hare = hare.next.next;
        tortoise = tortoise.next;
        if (hare === tortoise) return true;
      }
      return false;
    };
    

    链表有环,判断链表环的起始位置

    使用上面的算法,我们可以判断 链表是否有环

    如果有环,haretortoise 总会相遇,假设 tortoise 跑了 k 步,那么 hare 就跑了 2k 步,因为 hare 的速度是 tortoise 的两倍。

    那么环的长度就是 k

    此时我们再假设 相遇点环的起点m,那么链表的起点到环的起点就是 k - m 的长度,相遇点再继续前进 k - m 步也会到环的起点,因为环的长度就是 k 嘛。

    那么我们可以让 tortoise 和 hare,一个重回到链表的起点,一个从当前相遇点开始同步前进,一次一步。那么走了 k - m 步后它们就会相遇。

    // 这里让 tortoise 回到起点
    while (hare != tortoise) {
      hare = hare.next;
      tortoise = tortoise.next;
    }
    return hare;
    

    完整的代码如下:

    /**
     * @param {ListNode} head
     * @return {ListNode}
     */
    var detectCycle = function(head) {
      if (!head) return null;
      let hare = head;
      let tortoise = head;
    
      //找到相遇点
      while (hare && hare.next) {
        hare = hare.next.next;
        tortoise = tortoise.next;
        if (hare === tortoise) break;
      }
    
      // 没有相遇点,也就是没有环,直接返回即可
      // 无环情况下,且结点数为奇数个时,hare指向最后一个结点
      if (hare != tortoise) return null;
    
      //让tortoise指针回到开头,两指针重新同步前进,它们就会在环的起点相遇
      tortoise = head;
      while (tortoise !== hare) {
        hare = hare.next;
        tortoise = tortoise.next;
      }
      return hare;
    };
    

    总结

    Floyd's cycle-finding algorithm 既是 tortoise and the hare algorithm,也是 双指针的快慢指针法

    此算法主要应用在链表的 判断链表是否有环 以及 如果链表有环,找出环的起始位置

  • 相关阅读:
    【转载】最常见的数据类型映射列表
    【自然框架 NatureFramework】 项目结构、命名空间和命名规范
    【自然框架之SSO】实现SSO的一个初步想法
    两张图说明三层的奥义!
    Android中文API(146) —— Display
    [视频监控][海康威视]二次开发 网友文章转载贴
    Android中文API(141) —— GridLayout
    Android支持横行滚动的ListView控件
    Android应用开发提高系列(5)——Android动态加载(下)——加载已安装APK中的类和资源
    [WinForm]DataGridView通过代码新增行问题
  • 原文地址:https://www.cnblogs.com/AuKing/p/14037900.html
Copyright © 2011-2022 走看看