The sword refers to Offer-question 23 (Java Edition): the entry node of the ring in the linked list

Reference from: "Sword Pointing Offer - Famous Enterprise Interviewer Talking About Typical Programming Questions"

Topic : Entry Node of a Ring in a Linked List
If a linked list contains a ring, how to find the entry node of the ring?

The main idea :
Step 1: Determine whether the linked list has a cycle . With dual pointers, one pointer (slow pointer) takes one step at a time, and the other pointer (fast pointer) takes two steps at a time. If the fast pointer catches up with the slow pointer, there is a cycle, otherwise the linked list has no cycle.
Step 2 : Find the length L of the ring . The node where the fast and slow pointers meet in the first step must be in the ring (because the fast and slow pointers can only meet when they circle in the ring). Therefore, starting from this node of encounter, counting while moving, when returning to the node again, the length L of the ring can be obtained.
Step 3 : Find the entrance to the ring . Using double pointers, the first pointer takes L steps first, and the second pointer moves from the beginning, and the speed of both pointers is one step at a time. When the second pointer points to the entrance of the ring, the first pointer has walked around the ring to return to the entrance, that is, the node where the two pointers meet is the entrance of the ring.

The key point : simplify the complex, step by step

Time complexity : O(n)

public class EntryNodeOfLoop
{
    public static void main(String[] args)
    {
        ListNode head = testData();
        ListNode result = entryNodeOfLoop(head);
        if (result == null) return;
        System.out.println(result.val); //2
    }

    private static ListNode testData()
    {
        ListNode head = new ListNode(1);
        ListNode head2 = new ListNode(2);
        ListNode head3 = new ListNode(3);
        ListNode head4 = new ListNode(4);
        head.next = head2;
        head2.next = head3;
        head3.next = head4;
        head4.next = head2;  //尾节点和节点2构成环
        return head;
    }

    private static ListNode entryNodeOfLoop(ListNode pHead)
    {
        //查找相遇的节点
        ListNode meetingNode = findMeetNode(pHead);
        if (meetingNode == null) return null;
        //计算环的长度
        int loopLength = computeLoopLength(meetingNode);

        ListNode before = pHead; //前面的快指针
        ListNode after = pHead; //后面的慢指针
        for (int i = 0; i < loopLength; i++)
        {
            before = before.next;
        }
        while (before.val != after.val)
        {
            before = before.next;
            after = after.next;
            if (before.val == after.val) break;
        }
        return before;
    }

    /**
     * 查找相遇的节点
     *
     * @param pHead
     * @return
     */
    private static ListNode findMeetNode(ListNode pHead)
    {
        if (pHead == null) return null;
        ListNode slow = pHead.next;
        if (slow == null) return null;
        ListNode fast = slow.next;
        while (slow != null && fast != null)
        {
            if (slow.val == fast.val) return fast;
            //慢指针走一步
            slow = slow.next;
            //快指针走两步
            fast = fast.next;
            if (fast != null) fast = fast.next;
        }
        return null;
    }

    /**
     * 计算环的长度
     *
     * @param node
     * @return
     */
    private static int computeLoopLength(ListNode node)
    {
        ListNode runNode = node;
        int length = 1;
        runNode = runNode.next;
        //回到原节点,则求出长度
        while (node.val != runNode.val)
        {
            runNode = runNode.next;
            length++;
        }
        return length;
    }
}

class ListNode
{
    int val;
    ListNode next = null;

    ListNode(int val)
    {
        this.val = val;
    }
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325951590&siteId=291194637