1. 程式人生 > >鏈表中環的入口結點

鏈表中環的入口結點

否則 pre pub tps urn nal 一個 指針 描述

鏈表中環的入口結點

題目描述

給一個鏈表,若其中包含環,請找出該鏈表的環的入口結點,否則,輸出null。

第一步兩個節點, 一快一慢, 若有環則相遇

當快慢節點相遇時, 慢結點走了x個節點, 快結點恰巧走了2x個節點, 2x = k*n + x, k為1, 2,..., 此時令其中一個節點等於頭結點, 然後以相同速度移動兩個節點, 相遇時恰好為環的入口節點

class Solution {
public:
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        if ((nullptr == pHead) || (nullptr == pHead->next)) {
            return nullptr;
        }
        ListNode *pNode1 = pHead;
        ListNode *pNode2 = pHead;
        
        while ((nullptr != pNode2) && (nullptr != pNode2->next)) {
            pNode1 = pNode1->next;
            pNode2 = pNode2->next->next;
            
            if (pNode1 == pNode2) {
                pNode2 = pHead;
                while (pNode1 != pNode2) {
                    pNode1 = pNode1->next;
                    pNode2 = pNode2->next;
                }
                return pNode1;
            }
        }
        return nullptr;
    }
};

利用快慢節點確定有無環若有則返回相交節點, 否則返回nullptr

然後利用相交節點確定環的中節點的個數N

再讓一個節點指向頭結點, 一個指針指向距頭結點第N個節點, 然後以相同速度同時移動兩個節點, 相遇時即為環的入口點

class Solution {
public:
    // 利用快慢節點移動速度不同, 若有環, 快慢節點必相遇
    ListNode *MeetingNode(ListNode* pHead) {
        if (nullptr == pHead) {
            return nullptr;
        }
        
        ListNode *pSlow = pHead->next;
        if (nullptr == pSlow) {    // 若只有兩個節點則不能組成環
            return nullptr;
        }
        
        ListNode *pFast = pSlow->next;
        
        while((nullptr != pSlow) && (nullptr != pFast)) {
            if (pSlow == pFast) {
                return pSlow;
            }
            pSlow = pSlow->next;
            //pFast = pSlow->next;    // 沒有判斷pFast移動後是否是空節點
            pFast = pFast->next;    // 需要判斷pFast是不是空節點
            if (nullptr != pFast) {
                pFast = pFast->next;
            }
        }
        
        return nullptr;
    }
    
    ListNode* EntryNodeOfLoop(ListNode* pHead)
    {
        ListNode *meetingNode = MeetingNode(pHead);
        if (nullptr == meetingNode) {
            return nullptr;
        }
        
        // 得到環節點的數目
        ListNode *ct = meetingNode;
        int counts = 1;
        while (ct->next != meetingNode) {
            counts++;
            ct = ct->next;
        }
        
        // 確定環的入口
        ListNode *pNode1 = pHead;    // pNode1指向頭結點
        ListNode *pNode2 = pHead;    // pNode2先移動counts節點數目
        for (int i = 0; i < counts; i++) {
            pNode2 = pNode2->next;
        }
        while (pNode1 != pNode2) {
            pNode1 = pNode1->next;
            pNode2 = pNode2->next;
        }
        
        return pNode1;
    }
};
/*
struct ListNode {
    int val;
    struct ListNode *next;
    ListNode(int x) :
        val(x), next(NULL) {
    }
};
*/

鏈表中環的入口結點