剑指offer:链表中环的入口结点

题意描述

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

解题思路

一、使用集合

使用一个Set/List集合,遍历链表,当出现第一个重复节点时,就是环的节点。

    public ListNode EntryNodeOfLoop(ListNode pHead){
            if(pHead == null) return null;	//链表为空
            HashSet<ListNode> set = new HashSet<>();
            ListNode node = pHead;
            while(node != null){
                if(set.contains(node)){	//出现重复节点
                    return node;
                }else{
                    set.add(node);
                    node = node.next;
                }
            }
            return null;
    }

二、使用快慢指针

使用两个指针,快指针fast,慢指针slow

让两个指针从头向后移动,fast每次移动两个节点,slow每次移动一个节点,如果链表存在环的话,两个指针一定会相遇。在相遇时,假设slow走了x步,那么fast一定走了2x步。

同时,可以发现fast多走的x步一定是走在环上,也就是说,x是环的长度n的整数倍,即有如下公式: 2x=x+k∗nk=1,2,3,…

也就说,让一个指针指向环上的相遇点,一个指针指向头结点,同时以步长为1往后走,其碰头的那个结点,就是入口结点。

    public ListNode EntryNodeOfLoop(ListNode pHead){
            if(pHead == null || pHead.next == null)  return null;
            ListNode fast = pHead.next.next;	//快指针
            ListNode slow = pHead.next;	//慢指针
            while(fast != null){
                if(fast == slow){	//找到fast 与 slow 的相遇节点
                    fast = pHead;
                    while(fast != slow){
                        fast = fast.next;
                        slow = slow.next;
                    }
                    return fast;	//返回两指针再次相遇的节点
                }
                fast = fast.next.next;
                slow = slow.next;
            }
            return null;
        }
posted @ 2020-04-21 21:14  灵图  阅读(95)  评论(0)    收藏  举报