鏈表中環的入口結點
阿新 • • 發佈:2019-03-10
否則 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) {
}
};
*/
鏈表中環的入口結點