循环链表(笔记)

循环链表:如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。

方法:用快慢指针slow和fast,slow和fast指向链表的开始,slow一次走一步,fast一次走两步。不带环,fast就会为空;带环,fast就会在环里追上slow。

延伸问题:1、为什么slow和fast一定会在环中相遇?会不会在环里错过,永远遇不上?证明。

2、为什么slow走一步,fast走两步,能不能fast走一次走n步?证明一下。

第一步:slow和fast,fast一定是先进环,这时slow走入了环前距离的一半;

第二步:随着slow进环,fast已经在环里走了一段,走了多少跟环的大小有关系。假设slow进环的时候,slow跟fast的距离是N,fast开始追slow,slow每往前走一步,fast往前走两步,每追一次,判断一下相遇,每追一次,fast和slow的距离变化:N,N-1,N-2,...0。每追一次,距离 减少1,他们之间的距离减少到0的时候就是相遇的点。

假设:slow一次走一步,fast一次走三步,slow进环后,fast跟slow之间的距离为N,fast开始追slow,他们之间的距离变化如下

       如果N是奇数,距离变成-1意味着他们之间的距离变成C-1(C是环的长度),如果C-1是奇数,就永远追不上了;如果C-1是偶数,就可以追上。因此只能slow走一步,fast走两步,不能fast走一次走n步。

       slow走一步,fast走两步,一定会相遇。如何求环的入口点?结论:一个指针从相遇点开始走,一个指针从链表头开始走,他们会在环的入口点相遇。

      追上相遇的过程中,慢指针走的距离:L+X,。快指针走的距离:L+N*C+X,N(N>=1)是他们相遇之前,fast在环里走的圈数。

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
bool hasCycle(struct ListNode *head) {
    if(pHead == NULL || pHead->next == NULL)
    return NULL;
    struct ListNode* slow=head,*fast=head;
    while(fast&&fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
        if(fast==slow)
        {
            struct ListNode *meet=slow;//相遇点
        while(meet!=head)
        {
            meet=meet->next;
            head=head->next;
        }
        return meet;
        }
    }
    return NULL;
}

例题

1.环形链表(力扣)

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
bool hasCycle(struct ListNode *head) {
    struct ListNode* slow=head,*fast=head;
    while(fast&&fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
        if(fast==slow)
        {
            return true;
        }
    }
    return false;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值