题目要求:
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false
思路:
由于是环形链表,所以当链表开始循环遍历后,会进入死循环
通过快慢指针的方式解决问题,当快指针进入循环的时候,慢指针还未进入
如果fast指向NULL,则意味着无环
如果带环,当两者都进入环中时,可以理解为初中所学的追击问题,最终快慢两者会相遇
所以是否带环的判断条件就是fast==slow
代码实现:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include<stdbool.h>
//给你一个链表的头节点 head ,判断链表中是否有环。
//如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。
//为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)
//注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
//如果链表中存在环 ,则返回 true 。 否则,返回 false 。
//通过快慢指针的方式解决问题,追及问题
struct ListNode
{
int val;
struct ListNode *next;
};
bool hasCycle(struct ListNode* head)
{
struct ListNode* slow = head, * fast = head;
while (fast&&fast->next!=NULL)
{
slow = slow->next;
fast = fast->next->next;
if (slow==fast)
{
return true;
}
}
return false;
}
拓展思考:
如果fast一次走2步,slow一次走1步,那么两者最终一定能追上,相当于每次fast与slow中的距离缩小1
如果fast一次走3步,slow一次走1步,那么两者不一定能追上,甚至可能会死循环永远追不上
当n为偶数时,最后距离为0,即相遇
当n为奇数时,最后距离为-1,即反超,进入新的追逐,假设环的周长为C,则此时他们之间的距离为C-1
①C-1为偶数,能追上
②C-1为奇数,永远都追不上
在判断了是否相遇后,需要思考如何才能找到链表进环的结点
这里同样使用快慢指针的方式,一个指针从两个相遇的meet处出发,另一个指针从链表的头节点处出发,这两者最终会在进环的结点相遇
slow:L+X fast:L+nC+X
所以,L+nC+X=2(L+X)
所以nC-X=L
代码实现:
struct ListNode* detectCycle(struct ListNode* head)
{
struct ListNode* slow = head, * fast = head;
while (fast&&fast->next)
{
//慢走一步,快走两步
slow = slow->next;
fast = fast->next->next;
if (slow==fast)//当两者在meet位置相遇时
{
struct ListNode* meet = slow;
while (head!=meet)
{
head = head->next;//头结点向后推进
meet = meet->next;//meet在环内循环
}
//当while循环结束时,meet==head,即进环位置
return meet;
}
}
return NULL;
}
本文含有隐藏内容,请 开通VIP 后查看