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,也是 双指针的快慢指针法

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

  • 相关阅读:
    第五周任务以及结对编程
    “爆打”团队阿尔法发布 以及 第四周任务
    第三周内容
    爆打第一次站立会议
    3.23日PSP
    NABCD模型
    个人对结对编程的体会
    Fantacy团队第一次站立会议
    图形设想(简图)
    3月20日随笔
  • 原文地址:https://www.cnblogs.com/AuKing/p/14037900.html
Copyright © 2011-2022 走看看