1.判断单链表内是否有环?
- 设置两个指针,一个快指针,一个慢指针,起初都指向头结点
- 让快指针一次走两步,满指针一次走一步,如果链表内有环的话,经过一定次数后,快慢指针会相遇,则证明链表内有环(可参照下图例子)
struct ListNode
{
int val;
ListNode* next;
}
class Solution{
public:
bool hasCycle(ListNode* head){
if(head==NULL)
return NULL;
ListNode* slow=head;
ListNode* fast=head;
while(fast->next!=NULL&&fast->next->next!=NULL)
{
fast=fast->next->next;
slow=slow->next;
if(slow==fast)
{
return true;
break;
}
}
return NULL;
}
};
2.找环入口问题
-
首先判断链表是否有环
-
如果有环则开始找环的入口
-
创建两个指针,一个快指针,一个慢指针,都指向头结点,快指针一次走两步,慢指针一次走一步,因此可以得出快指针所走的步数是慢指针的两倍(下图简单画出)
-
假设A为环的入口,B为快慢指针第一次相遇的位置,a为到环入口的距离,b为入环口到相遇位置的距离,c为剩余的距离
-
当快慢指针第一次相遇时,慢指针所走的距离应该为(a+b),快指针走的距离应该为(a+b+c+b);上面我们知道了快指针是慢指针所走长度的两步,因此2*(a+b)=(a+b+c+b),由此可得c=a;
-
慢指针继续走,再创建一个指针从头开始走,当它们第一次相遇时,此时的位置就是环的入口
struct ListNode
{
int val;
ListNode* next;
}
class Solution
{
public:
ListNode *detectCycle(ListNode* head){
if(head==NULL)
return NULL;
ListNode* fast=head;
ListNode* slow=head;
bool hascycle=false;
while(fast->next!=NULL&&fast->next->next!=NULL) //判断是否有环
{
fast=fast->next->next;
slow=slow->next;
if(slow==fast)
{
hascycle=true;
break;
}
}
if(hascycle) //找到入环节点
{
ListNode* p=head;
while(p!=slow)
{
p=p->next;
slow=slow->next;
}
return p;
}
else
return NULL;
}
};