给你一个链表的头节点 head ,判断链表中是否有环.
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况.
如果链表中存在环 ,则返回 true 。 否则,返回 false .
OJ链表
// 判断链表是否有环
bool hasCycle(ListNode *head) {
if (head == NULL || head->next == NULL) {
// 空链表或只有一个节点的链表不可能有环
return false;
}
ListNode *slow = head;
ListNode *fast = head->next;
// 快慢指针开始移动,直到它们相遇或快指针到达链表尾部
while (slow != fast) {
// 如果快指针到达链表尾部,说明没有环
if (fast == NULL || fast->next == NULL) {
return false;
}
slow = slow->next; // 慢指针每次移动一个节点
fast = fast->next->next; // 快指针每次移动两个节点
}
// 如果快慢指针相遇,说明有环
return true;
}
【思路】
快慢指针,即慢指针一次走一步,快指针一次走两步,两个指针从链表其实位置开始运行,如果链表带环则一定会在环中相遇,否则快指针率先走到链表的末尾。
【扩展问题】
- 为什么快指针每次走两步,慢指针走一步可以?
假设链表带环,两个指针最后都会进入环,快指针先进环,慢指针后进环。当慢指针刚进环时,可能就和快指针相遇了,最差情况下两个指针之间的距离刚好就是环的长度。此时,两个指针每移动一次,之间的距离就缩小一步,不会出现每次刚好是套圈的情况,因此:在满指针走到一圈之前,快指针肯定是可以追上慢指针的,即相遇。
- 快指针一次走3步,走4步,…n步行吗?
假设:快指针每次走三步,慢指针每次走一步, 此时快指针肯定先进环。假设慢指针进环的时候,快指针的位置如图所示
此时按照上述方法来环绕移动
当快指针每次走三步,慢指针每次走一步时,它们之间的相对速度差是两步。这意味着快指针相对于慢指针每次都会拉近两个节点的距离。但是,如果环的大小(即环中节点的数量)是快指针和慢指针速度差的倍数(即环的大小是2的倍数),那么快指针可能会“套圈”慢指针而不相遇。具体来说,如果环的大小是2的倍数(比如4、6、8等),那么快指针会在到达环的起点之前追上慢指针,但会在慢指针之后再次到达起点,从而不会相遇。
举个例子,假设环的大小是4个节点,快指针每次走三步,慢指针每次走一步。当慢指针走完一圈回到起点时,快指针已经走了三圈,即12个节点,并回到了起点之后两个节点的位置。因此,它们不会在同一位置相遇。
然而,如果环的大小不是快指针和慢指针速度差的倍数,那么快指针最终还是会与慢指针相遇。这是因为在这种情况下,快指针和慢指针的相对位置会在环中不断发生变化,直到它们在某个节点相遇。
但为什么快指针走两步,慢指针走一步可以确保相遇呢?这是因为无论环的大小是多少,快指针都会在环中追上慢指针。具体来说,假设环的大小为n,那么当慢指针走了x圈时(x为正整数),快指针会走了2x圈。由于它们都在环中移动,所以它们最终会在某个节点相遇。
因此,虽然快指针每次走三步或更多步在理论上是可行的(只要处理好空指针和尾部的情况),但在实践中,快指针每次走两步,慢指针走一步是一种更简单、更可靠的方法来检测链表中的环。
所以只有快指针走两步,慢指针走一步才可以,因为换的最小长度是一,即使套圈了两个也在相同的位置.