带环链表问题

带环链表就是字面意思带环的链表,例如以下这三种情况

 练习题

1.给定一个链表,判断链表中是否带环. - 力扣(LeetCode)

思路:快慢指针,慢指针走一步,快指针走两步,两个指针从链表的起始位置开始走,如果链表带环,快慢指针一定会在环中相遇,否则快指针先走到链表的末尾。

 

 

 当slow指针进环时,fast和slow追及(一定能追上),证明过程如下

 证明:假设slow进环时,与fast指针相距N,快慢指针的速度差为1,所以快慢指针之间的距离变化为

N->N-1->N-2->N-3->........->2->1->0,每追击一次,距离减小1,当减小为0时,就是追上了,这里最差的情况就是两个指针之间的距离刚好就是环的长度。

 所以,在慢指针走一圈之前,快指针肯定是可以追上慢指针的

问题扩展:

1.快指针走一次走3步,4步,n步可以吗?

当快指针走3步时,两指针之间的距离变化为

偶数              奇数

N                   N

N-2                N-2

N-4                N-4

...                     ...

4                        3

2                         1

0(追上了)            -1(错过了进行新一轮的追击),快慢指针之间的距离变为C-1(C为环的长度),这里又有两种情况,C-1分为奇数和偶数

总结:

1.N是偶数,第一轮就追上了

2.N是奇数,第一轮就会错过,距离变为C-1

   a.如果c-1是偶数,下一轮就追上

   b.如果c-1是奇数,就永远也追不上了

所以,如果同时存在N是奇数和C是偶数,就永远追不上(实际上这种情况并不存在)

证明:假设slow进环时,fast和slow之间的距离为N,此时fast已在环里走了x圈,slow走的距离为L,fast走L+x*C+C-N,fast走的距离是slow的3倍

3*L=L+x*C+C-N

2*L=(x+1)*C-N,如果同时存在N是奇数和C是偶数,这个等式就不成立,C和N只能同时为奇数或者偶数

结论:一定能追上,N为偶数第一轮就追上,N为奇数第一轮追不上,但C-1为偶数第二轮就可以追上。

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

2.给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。. - 力扣(LeetCode)

结论:相遇后,slow指针指针继续走,cur指针起始位置开始走,相遇的位置就是入环的第一个节点

证明:slow指针走过的距离L+N,fast走的为L+N+C*x,fast走过的距离是slow的2倍

2*(L+N)=L+N+C*x

L=C*x-N=(x-1)*C+(C-N)x>=1

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
 typedef struct ListNode ListNode;
struct ListNode *detectCycle(struct ListNode *head) {
    ListNode*slow=head;
    ListNode*fast=head;
    while(fast&&fast->next)
    {
        slow=slow->next;
        fast=fast->next->next;
        if(slow==fast)
        {
            ListNode*meet=slow;
            while(meet!=head)
            {
                head=head->next;
                meet=meet->next;
            }
            return meet;
        }
    }
    return NULL;
}

  • 15
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值