分析:使用快慢指针,快指针一次走两步,慢指针一次走一步
快指针在环内追赶慢指针,如果两个指针相遇,则证明存在环
证明:
1️⃣环的起点为链表的尾节点,当fast指针到达环的起点时,slow指针走到链表的一半
2️⃣当slow指针到达环的起点时,fast指针指向环内的某个节点
3️⃣此时快慢指针的差距为N,fast指针一次走两步,slow指针一次走一步,两个指针的差距每次缩小1,N次之后,两个指针的差距缩小为0,即两指针相遇
bool hasCycle(struct ListNode *head) {
struct ListNode* slow, *fast;
slow = fast = head;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
//快指针赶上了慢指针,存在环
if(fast == slow)
{
return true;
}
}
return false;
}
方法一:
首先要判断链表是否有环,非环形链表返回NULL,环形链表才有下述操作
由上图:
fast指针每次走两步,slow指针每次走一步,所以有2(L+x) = L+x+N*C
L = N*C - x = (N-1)*C + C - x
即如果有一个指针从头开始走,当它走过L到达环的入口时,有一个指针从相遇点meet走,他绕环N-1圈,再走C-x,同时也到达环的入口
所以我们使用两个指针,一个head链表头开始走,一个meet从相遇点开始走,每次走一步,当这两个指针不等时,head = head->next,meet = meet->next;当这两个指针相等时,即为环的入口节点
struct ListNode *detectCycle(struct ListNode *head)
{
struct ListNode* slow, *fast;
slow = fast = head;
struct ListNode* tail = head;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
//存在环,返回入环的第一个节点
if (fast == slow)
{
//找到相遇点
struct ListNode* meet = slow;
while(meet != head)
{
meet = meet->next;
head = head->next;
}
//相遇即为环的入口
return meet;
}
}
return NULL;
}
方法二:转换成相交链表问题
我们已经很熟练的可以找到环中fast指针和slow指针的相遇点
由上图,我们可以将环形链表分成两部分
一个以head作为头,meet作为尾
另一个以meet->next作为头,meet作为尾
环的入口是这两个链表相交的位置,已经讲述过链表相交问题【leetcode】160.相交链表_李斯啦果的博客-CSDN博客
因此求环的入口即转换成求两个链表相交位置的问题
📖Note
断开链表会更改原链表,因此求出交点后需要恢复原链表的结构文章来源:https://www.toymoban.com/news/detail-628886.html
//方法二:转换成相交链表问题
struct ListNode* getIntersectionNode(struct ListNode* headA, struct ListNode* headB) {
struct ListNode* curA = headA;
struct ListNode* curB = headB;
int lenA = 0;
int lenB = 0;
//统计长度
while (curA)
{
lenA++;
curA = curA->next;
}
while (curB)
{
lenB++;
curB = curB->next;
}
struct ListNode* longList = headA, * shortList = headB;
if (lenA < lenB)
{
longList = headB;
shortList = headA;
}
int gap = abs(lenA - lenB);
//长链表先走差距步
while (gap--)
{
longList = longList->next;
}
//同时走
while (longList != shortList)
{
longList = longList->next;
shortList = shortList->next;
}
return longList;
}
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode* slow, *fast;
slow = fast = head;
struct ListNode* tail = head;
while (fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
//存在环,返回入环的第一个节点
if (fast == slow)
{
//转换成相交链表问题
struct ListNode* next = slow->next;
//断开环
slow->next = NULL;
struct ListNode* entryNode = getIntersectionNode(head,next);
//恢复环
slow->next = next;
return entryNode;
}
}
return NULL;
}
文章来源地址https://www.toymoban.com/news/detail-628886.html
到了这里,关于【leetcode】141.环形链表的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!