1. 程式人生 > 其它 >【連結串列】23題-連結串列中環的入口節點

【連結串列】23題-連結串列中環的入口節點

技術標籤:劍指Offer演算法資料結構

1 題目描述

如果一個連結串列中包含環,如何找出環的入口節點?

2 解題思路

解決這個問題的第一步是如何確定一個連結串列中包含環。我們可以用兩個指標來解決這個問題。定義兩個指標,同時從連結串列的頭節點出發,一個指標一次走一步,另一個指標一次走兩步。如果走得快的指標追上了走得慢的指標,那麼連結串列就包含有環;如果走得快的指標走到了連結串列的末尾都沒有追上第一個指標,那麼連結串列就不包含環。
在這裡插入圖片描述

第二步是如何找到環的入口。我們還是用兩個指標來解決這個問題。先定義兩個指標p1和p2指向連結串列的頭節點。如果連結串列中的環有n個節點,則指標p1先在連結串列上向前移動n步,然後兩個指標以相同的速度向前移動。當第二個指標指向環的入口節點時,第一個指標已經圍繞著環走了一圈,又回到了入口節點。

剩下的問題是如何得到環中節點的數目。我們在前面提到判斷一個連結串列裡是否有環時用到了一快一慢兩個指標。如果兩個指標相遇,則表明連結串列中存在環。兩個指標相遇的節點一定是在環中。可以從這個節點出發,一邊繼續向前移動一邊計數,當再次回到這個節點時,就可以得到環中節點數了。

package section5_5;

public class Solution {

    private static class ListNode {
        int val;
        ListNode next;
        ListNode(int x) { val = x; }
    }
ListNode meetingNode(ListNode head) { if (head == null) { return null; } ListNode slow = head.next; if (slow == null) { return null; } ListNode fast = slow.next; while (fast != null && slow != null) { if
(fast == slow) { return fast; } slow = slow.next; fast = fast.next; if (fast != null) { fast = fast.next; } } return null; } ListNode entryNodeOfLoop(ListNode head) { ListNode meeting_node = meetingNode(head); if (meeting_node == null) { return null; } int nodesInLoop = 1; ListNode node1 = meeting_node; while (node1.next != meeting_node) { node1 = node1.next; ++nodesInLoop; } node1 = head; for (int i = 0;i < nodesInLoop;i++) { node1 = node1.next; } ListNode node2 = head; while (node1 != node2) { node1 = node1.next; node2 = node2.next; } return node1; } //測試用例 public static void main(String[] args) { ListNode node = new ListNode(0); ListNode head = node; for (int i = 1;i < 7;i++) { node.next = new ListNode(i); node = node.next; } node = head; ListNode cur1 = node; while (cur1.val != 3) { cur1 = cur1.next; } //System.out.println(cur1.val); ListNode cur2 = node; while (cur2.val != 6) { cur2 = cur2.next; } //System.out.println(cur2.val); cur2.next = cur1; Solution solution = new Solution(); System.out.println(solution.entryNodeOfLoop(head).val); } }