版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Sea_muxixi/article/details/82662011
题意:给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
思路:
方法一:把链表遍历一遍,如果没有重复节点,则没有环;如果有重复节点,第一个重复节点就是环的入口。
时间复杂度O(n),空间复杂度O(n)。
因为需要额外的数组去记录该节点有没有被访问过。
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
ListNode* now = pHead;
map<ListNode*, bool> vis;
ListNode* ans = NULL;
while (now != NULL)
{
if (vis[now] == false)
{
vis[now] = true;
}
else
{
ans = now;
break;
}
}
return ans;
}
};
方法2:一快一慢两个指针,同时前进,如果相遇,则有环;不相遇,则无环。
对于有环的情况,在相遇节点,继续往前,再次回到相遇节点,这是经过的节点数就是环的节点数。
考虑总结点数为s,环中的节点数为n,那么非环的节点数为l=s-n;
所以只要从头结点遍历l个节点,那个节点就是环的入口;
或者也可以让一个指针先从头结点走n步,另一个指针再从头节点出发;
两个指针相遇的节点就是入口节点。
class Solution {
public:
ListNode* EntryNodeOfLoop(ListNode* pHead)
{
if (pHead == NULL) return NULL;
ListNode* meetNode = meet(pHead);
if (meetNode == NULL) return NULL;
int nodeCount = 1;
ListNode* now = meetNode;
while (now->next != meetNode)
{
now = now->next;
nodeCount++;
}
ListNode* node1 = pHead;
for (int i = 0; i < nodeCount; i++)
node1 = node1->next;
ListNode* node2 = pHead;
while (node1 != node2)
{
node1 = node1->next;
node2 = node2->next;
}
return node1;
}
ListNode* meet(ListNode* pHead)
{
if (pHead == NULL) return NULL;
ListNode* slow = pHead->next;
if (slow == NULL) return NULL;
ListNode* fast = slow->next;
while (slow != NULL && fast!=NULL)
{
if (slow == fast) return slow;
slow = slow->next;
if (fast->next != NULL && fast->next->next != NULL)
fast = fast->next->next;
else
return NULL;
}
return NULL;
}
};