链表带环问题OJ

链表是否带环

结论:定义快慢指针,快指针一次走2步,满指针一次走1步,如果链表带环,他们会在环中某个位置相遇,如果不带环,快指针则会为空或者走到尾(奇数个结点,偶数个结点)

1、为什么slow走1步,fast走2步,他们会相遇?会不会错过?请证明

1.fast先进环,slow走了入环距离的一半。

2.slow进环,fast已经在环中走了一段,具体在哪和圆环的大小有关系

不管是大于slow还是小于slow,等于就正好相遇,他们都会有一个小于圆周长C的距离N,

再根据slow一次走1步,fast一次走2步,每次他们之间的距离N都减小1

每追1次,他们的距离变化:N

                                             N-1

                                             N-2

                                             ...

                                             2

                                             1

                                             0

0意味着他们相遇了

 


2、为什么slow走1步,fast走n步(n>=3),他们会相遇?会不会错过?请证明

假设slow进环的时候fast和slow距离为N

fast走3步,slow走1步,他们每追一次距离会缩小2

那么他们的距离变为就是:N   (N是偶数)   N   (N是奇数)   

                                           N-2                 N-2

                                           N-4                 N-4

                                           ...                    ...

                                           4                       3

                                           2                       1

                                           0 追上了                -1  这一次追不上  ->相当于距离变成C-1,相当于进入新的一轮追击

                                                                如果C-1是奇数,那么下一次还是会变成C-1,那么就永远

追不上了                                                 如果C-1是偶数,那么就可以追上

关于N-3 或者N-某值,他们最后会剩下几取决于  例如:N-3  某数%3 范围只有0~2,那么也就是如果不是3的倍数,只能是0,1,2

不管fast走几步,slow走几步,他们之间每次追击,只要令距离每次-1,就可以追上,例如:slow每次走2步,fast每次走3步,也是一样每次距离减少1,也可以追上,N不是奇数就是偶数,每次减1,总能追上

 附上代码:

 bool hasCycle(struct ListNode *head) 
{
    struct ListNode *fast=head,*slow=head;
    while(fast && fast->next)//奇数个节点和偶数个节点如果不带环 结束条件的不同
    {
        fast = fast->next->next;
        slow = slow->next;
        if(fast == slow)
        return true;
    }
    return false;

}

给定一个链表的头节点 head ,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

结论:如果有环,一个指针从快慢指针相遇点开始走,另一个指针从链表头开始走,都是一次走1步,他们最终会在入环点相遇

根据判断链表是否带环中,快慢指针走过的距离关系,快指针走的距离是满指针走过的距离的2倍

可以证明会在入环点相遇

假设

起始点-入口点的距离: L

入口点-相遇点的距离: X   0<=X<C

环的长度: C

 当fast和slow相遇时

slow走过的距离是: L + X

fast走过的距离是: L+NC+X 

关于X ,X永远是小于环的长度,并且X == N

X == N 再没相遇之前fast和slow的距离是N,也就是说他们还要再追N次,而slow每次走1步,也就是走了N步,也就是X,所以X == N

 

并且N最大 是C-1  那么slow在相遇前的X也是C-1,所以X最多走C-1    X范围  0<=X<C 等于0是因为可能刚入环就相遇了

fast走过的距离是: L+NC+X 

根据过程看出来的 fast走过的路程,至少也要走一圈在环里面,即使环很大很大,也要走一圈

我是根据这个过程,肉眼看跑出来的。

如果圆很小那么fast会走很多圈

 当fast和slow相遇时

slow走过的距离是: L + X

fast走过的距离是: L+NC+X 

那么有了这两个式子,和fast和slow的二倍关系,可以写出

代码:

//结论:一个指针从头结点开始,另一个从相遇点开始,同时走,每次走1步,他们会在入口点相遇
struct ListNode *detectCycle(struct ListNode *head) 
{
    struct ListNode* slow,*fast;
    slow = fast = head;
    while(fast && fast->next)//奇数偶数情况结束,fast或者fast->next就会为空
    {
        slow = slow->next;
        fast = fast->next->next;
        if(slow == fast)
        {
            //相遇
            struct ListNode* cur,*meetnode;
            cur = head;
            meetnode = slow;
            while(meetnode != cur)//他们肯定会相遇,因为L=N*C-X N>=1
            {
                cur = cur->next;
                meetnode = meetnode->next;
            }

            return meetnode;
        }
    }
    return NULL;
}

求链表中环的长度 

//

求环的长度,在相遇点在用一个指针遍历一遍直到相等

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值