鏈表中環的入口結點

  AcWing打卡活動

《劍指Offer》打卡活動 

週二第十一題   鏈表中環的入口結點

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 * 思路
 * a. 確定是否是環鏈表
 *  使用兩個節點,一個節點一次走一步,一個節點一次走2步,
 *  這樣如果鏈表中有環的話,走兩步的節點是可以追上走一步的節點的
 * b. 確定環的大小,即環中有多少元素
 *  利用剛剛mettingNode()得到的相遇節點
 *  依舊使用兩個節點,一個節點停留在相遇節點,一個節點從相遇節點出發
 *  計數器++,直到兩個節點相遇
 * c. 確定環的入口節點
 *  兩個節點p1和p2, p1向前移動N(N=環中元素數)步,p2停留在頭結點
 *  p1和p2同時移動,直到相遇
 *  例子:
 *      1 2 3 4 5 6
 *  從4~6爲環
 *  則環中有3個節點,
 *  第一步、p1 先走3步,從節點4出發,p2 從頭結點出發
 *  第二步、p1,p2同時出發,一起走3步,p1 -> 1, 2, 3, 4, p2 -> 4, 5, 6, 4 相遇
 * 
 * 
 */
class Solution {
    public ListNode entryNodeOfLoop(ListNode head) {
        if(head == null) {
            return null;
        }
        // a.確定是否有環,拿到相遇節點
        ListNode metNode = meetingNode(head);
        if(metNode == null) {
            return null;
        }
        
        // b. 確定環中的元素數
        ListNode node = metNode.next;
        int nodesInLoop = 1;
        while(node != metNode) {
            node = node.next;
            nodesInLoop++;
        }
        // c、確定環的入口節點,需要兩個節點, 從頭開始走
        node = head;
        ListNode node2 = head;
        for(int i = 0; i < nodesInLoop; i++) {
            node = node.next;
        }
        // 一起走
        while(node != node2) {
            node = node.next;
            node2 = node2.next;
        }
        return node;
    }
    // a. 確定是否有環
    public ListNode meetingNode(ListNode head) {
        if(head == null) {
            return null;
        }
        ListNode slowNode = head;
        slowNode = slowNode.next;
        if(slowNode == null) {
            return null;
        }
        ListNode fastNode = slowNode.next;
        // 開始追
        while(fastNode != null && slowNode != null) {
            if(fastNode == slowNode) {
                return fastNode;
            }
            // 一次走一步
            slowNode = slowNode.next;
            // 一次走兩步
            fastNode = fastNode.next;
            if(fastNode != null) {
                fastNode = fastNode.next;
            }
        }
        // 如果出了while,則該鏈表沒有環
        return null;
    }
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章