Leetcode142 Linked List Cycle II 找出环形链表的入口节点

Linked List Cycle II
Given a linked list, return the node where the cycle begins. 
If there is no cycle, return null.
  • 首先找到meetingnode
    (快慢指针在圈里面循环最后一定会相交,并且是在慢指针的第一圈)
  • 制造二次相遇:重新定义两个指针,一个指针指向head, 一个指针指向快慢指向的相遇点,然后这两个指针不断遍历(同时走一步),当它们指向同一个结点时即是环的入口结点

在这里插入图片描述
假设上图中的 7 为快慢指针相遇的结点,不难看出慢指针走了 L + S 步****(一定会在第一圈遇到),快指针走得比慢指针更快,它除了走了 L + S 步外,还额外在环里绕了 n 圈,所以快指针经历了 L+S+nR 步(R为图中环的长度),另外我们知道每遍历一次,慢指针走了一步,快指针走了两步,所以快指针走的路程是慢指针的两倍,即 2 (L+S) =L+S+nR,即 L+S = nR(记住n=1的示例就好)

  • 当 n = 1 时,则 L+S = R 时,则从相遇点 7 开始遍历走到环入口点 2 的距离为 R – S = L,刚好是环的入口结点,而 head 与环入口点 2 的距离恰好也为 L,所以只要在头结点定义一个指针,在相遇点(7)定义另外一个指针,两个指针同时遍历,每次走一步,必然在环的入口位置 2 相遇
  • 当 n > 1时,L + S = nR,即 L = nR – S, nR-S 怎么理解?可以看作是指针从结点 7 出发,走了 n 圈后,回退 S 步,此时刚好指向环入口位置,也就是说如果设置一个指针指向 head(定义为p1), 另设一个指针指向 7(定义为p2),不断遍历,p2 走了nR-S 时(即环的入口位置),p1也刚好走到这里(此时 p1 走了 nR-S = L步,刚好是环入口位置),即两者相遇!
/**
 * 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||head.next==null){
            return null;
        }
        ListNode meetingnode= iscycle(head);
        if (meetingnode==null){
            return null;
        }
        //制造二次相遇
        ListNode fast=head;
        ListNode slow=meetingnode;
        while(fast!=slow){
            fast=fast.next;
            slow=slow.next;
        }
        return slow;
        
    }
    
    //找meetingnode
    ListNode iscycle(ListNode head){
            if(head==null||head.next==null){
                return null;
            }
            ListNode fast=head;
            ListNode slow=head;
            while(fast!=null&&fast.next!=null){//环和非环的条件
                fast=fast.next.next;
                slow=slow.next;
                if(fast==slow){
                    return slow;
                }
            }
            return null;

        }
}
  • 快慢指针相遇时,慢指针一定在第一圈,而快指针可能走了n圈
    【证明1】假设当慢指针进入环时,慢指针在快指针前 m 处(顺指针方向)(0<m<环长,如果 m=0 or m=环长 ,说明此时快慢指针正好在环入口处相遇),假设这之后快慢指针又移动了 x 次后相遇,此时慢指针移动的距离即为 x, 快指针移动的距离2x,两者相遇,则 x+m = 2x ⟹ x = m 。而m小于环长,所以慢指针一定在第一圈时就和快指针相遇。
  • 一个人是跳1个格子,另一个跳2个格子,会不会每次要相遇的时候,快的都会跳过慢的那个,从而不会相遇在一个格子。(重点是为什么一定会相遇在一个格子)

    证明:通俗点可以理解为他们的相对速度只差一个格子,快的只能一个一个格子的去追慢的,必然在一个格子相遇!如果没看懂,看下面的详细。一次跳2个与一次跳一个格子的追上之后,是一定会在一个格子遇到的。因为在即将追上的时候,快的那个落后慢的1个或者2个格子,无论哪种,落后1个的话,下一步正好追上,落后2个格子的话,下一步就落后1个格子了,也可以说即将追上的时候一定是相差1个格子,下一步一定在一个格子相遇。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值