链表中环的入口结点
题目描述
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出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) {
}
};
*/