找出有环单链表的入口节点

    这个题比较经典 ,使用两个指针去解决。一个快指针,一个慢指针。快指针每次走两步,慢指针每次走一步。如果两个指针相遇,那么这个链表是有环的。但是关键问题是链表环的入口节点在哪里呢?

 

    数学证明贴上来:设置整个链表的节点个数为N,环的节点个数为L,从链表头节点到环的入口节点距离为M,下文记作M节点。

假设慢指针走了k步之后两个节点相遇,将相遇的节点记作k节点。可以证明 0<=k<=N,(慢指针入环的时候,相对于快指针处于静止,快指针相对于慢指针的速度为1,所以快指针最坏情况下用L-1的步数就可以追上慢指针),而快指针走了2*k的步数。

   可以得知            2*k-k=x*L       (1) 这一点很好理解,从快指针第一次到达k节点,到后来快指针与慢指针相遇在k节点,中间的过程就是一直在环中绕圈,x为快指针在和慢指针相遇之前绕圈的次数。x是一个整数。可以得到 k=x*L  ,推理出k是L的整数倍。ps:特别注意k代表的是慢指针与快指针第一次相遇走的步数  而k节点只是一个名称。而M是链表头节点到环的入口节点的步数

提出第二个问题  那么此时 k节点与环的入口M节点有几步的距离呢?

   k的值肯定大于等于M的。因为两个指针相遇肯定是在环内。环的节点个数为L,M节点与k节点的距离为k-M;,那么k到M需要走的步数为 L-(k-M), 一定要理解这一点。自己可以画个图去试一下。所以 k到M的步数是L-k+M, 而链表头节点到环的入口节点的距离是M,我们再看看L-k代表什么呢?根据 k=x*L ,其实就是(1-x)*L,L是环的节点个数,如果有一个指针 i 指向 k节点,每次只能走一步,要去环的入口节点M,先从k节点出发,先走L-k的步数,其实就是绕圈(1-x)个圈,我们没必要在意(1-x)的正负,这个没有意义,如果是负数例如-2,只是说指针倒着转了两圈。但是它始终会回到 k 节点,然后再走M步,到达链表环的入口节点,如果此时同时有一个指针j从链表的头节点出发走M步到达M节点,那么 和 会同时在M节点处相遇。也就是说 ij 第一次相遇的节点就是我们的入口节点M。如果还有不理解的,可以私信我。或者在博客下面留言。

最后贴上代码便于理解

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public ListNode detectCycle(ListNode head) 
    {
        if(head==null) return null;
       ListNode fast=head;
       ListNode slow=head;
       while(fast!=null&&slow!=null&&fast.next!=null)
       {
           fast=fast.next.next;
           slow=slow.next;
           if(fast==slow)         // 先找到 k 节点
               break;
       }
       if(slow==null||fast==null||fast.next==null) return null;

      //如果找到了相遇的点 假设slow指针走了 k步  那么 slow指针指向的节点 就是我们的 k 节点 
       ListNode first=head; //这就是我们的 j 节点
       while(first!=slow)
       {
           first=first.next;
           slow=slow.next;
       }
        return first;
    }
}

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值