Floyd判圈算法(龟兔赛跑算法)记录

前言

这是在做 142. 环形链表 II 时看到的算法,在这里记录,方便以后复习和学习;

Floyd判圈算法(Floyd Cycle Detection Algorithm),又称龟兔赛跑算法(Tortoise and Hare Algorithm),是一个可以在有限状态机、迭代函数或者链表上判断是否存在环,以及判断环的起点与长度的算法。 – 百度百科

作用:判定链表中是否有环存在以及一些其他的作用,下面会具体说到

基本思想: 既然它的外号叫做“龟兔赛跑算法”,那肯定就要体现出乌龟和兔子的作用了,即一个跑得慢一个跑得快,如果有环的话,那么,兔子肯定是能追上乌龟的,而且追上的时候兔子多跑的路的长度是圈的长度的倍数。以下就用pH指针表示兔子,一次能跑两步(没病走两步……),pT指的是乌龟,一次能跑一步;

例子

这里就以 142. 环形链表 II 这题来记录一下:
题目说道:

Given a linked list, return the node where the cycle begins. If there is no cycle, return null.
Note: Do not modify the linked list.

也就是说,如果链表有环存在的话,就要返回第一个入环的节点,比如下图:
这里写图片描述

就应该返回的是2这个节点;而要找到这个入环节点,首先就要先判断是否有环,通过自己实验可以知道,当有环存在的时候,当兔子追到乌龟(在一起了= =|| )的时候:
这里写图片描述

这里写图片描述

这里写图片描述

从追到的这个地方开始,比如这里是节点4,从节点3到4的这个不考虑,然后从1和节点4开始往下遍历相同的步数,当遍历到的是同一个时即为入环结点:
这里写图片描述

则根据龟兔赛跑算法的思想,可以有如下的代码:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        // 龟兔赛跑算法
        ListNode* pH = head; // 兔子
        ListNode* pT = head; // 乌龟

        while(pH != NULL && pH->next != NULL && pH->next->next != NULL){ // 这里需要判断pH以及pH->next->next是否为NULL,但是如果pH->nextNULL的话就会有空指针异常,所以还要加一个pH->next是否为NULL的判断

            pT = pT->next;
            pH = pH->next->next;

            if(pT == pH){ // 有环,则接下来从龟兔相遇的地方开始作为head2
                // 将tempHead和head2同时移动相同的距离,相等的地方即为入环结点
                ListNode* head2 = pT;
                ListNode* tempHead = head;
                while(tempHead != head2){
                    tempHead = tempHead->next;
                    head2 = head2->next;
                }
                return head2;

            }
        }

        return NULL;


    }
};

总结

  1. 判断是否有环:只需要看pH和pT是否会相遇(遍历到同一个结点)即可,相遇的话就说明 有环;
  2. 确定入环结点:如上所述,这里不再赘述;
  3. 求环的长度:(1) 变量i记录从龟兔相遇的地方head2开始与head同时移动,多少次才相遇,结果再 +1,即为环形链表的结点个数;或者(2)相遇的时候,一定已经在环上了,然后兔子和乌龟只要再次在环上接着跑,再次相遇的时候,跑的快的那个人就比跑的慢的人整整多跑了一圈,所以环的长度也就出来了;
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值