目录
一.题目介绍
如何判断一个链表是否带环
像如下这样
解决办法就是用快慢指针来解决 定义一个慢指针每次走一步,一个快指针每次走两步,如果他们相等(快慢指针的值相等既为带环链表),如果不相等fast最后就会为NULL跳出循环,即不为带环链表。参考代码如下
// 函数定义
bool hasCycle(ListNode *head) {
if (head == NULL || head->next == NULL) {
return false;
}
ListNode *slow = head; // 慢指针
ListNode *fast = head->next; // 快指针
while (fast != NULL && fast->next != NULL) {
slow = slow->next; // 慢指针每次移动一步
fast = fast->next->next; // 快指针每次移动两步
if (slow == fast) { // 如果快慢指针相遇,则存在环
return true;
}
}
return false; // 如果快指针到达链表末尾,说明没有环
}
二.证明为何相等
但是可能有些朋友就会问了,为什么带环就一定会让fast与slow指针相等呢,有没有可能错过呢,不相等呢接下来我们来证明一下下。
(1)追击问题
当慢指针刚刚进入环内的时候是这个样子的(假设逆时针旋转)
也就是说当慢指针刚进入环内他们的距离之差为N,这时候由于快指针移动次数多(或者说速度更快)它将会缩短他们之间的距离 如果我们假设slow指针每次一步 fast指针每次两步
N-1
N-2
N-3
N-4
....
N=0
到最后N一定会等于0
当N等于0的时候就是相遇的时候
当然上面是假设了他们的速度,且差值为奇数,那如果把这个N或者速度的差值给奇特一点会不会不相遇造成死循环呢,比如说它们错过了呢
这里我先给出答案,我们要看速度的差值,这里我们假设一下当速度差值为一个偶数的时候(因为第一次错过的情况就在这)当N为偶数与奇数时
当N偶数 当N奇数
N-2 N-2
N-4 N-4
... ...
0 -1
可以很明显的看到当N为奇数 速度差为偶数的时候确实会错过一次,但是这种错过只是将他们之间的距离改变成了C-1 (假设圆环的周长为C)这时候的距离N就是圆环的周长-1
这时候又有两种情况,C为奇数与C为偶数的情况,C为奇数就说明C-1(就是距离N)为偶数 C为偶数就说明C-1(N)为奇数,我们再看看上的距离N,如果C为偶数的话变成死循环不可能相遇!!
哦哦哦 我们来总结一下下
总结一下:
1、N是偶数,第一轮就追上了
2、N就是,第一轮追击会错过,距离变成C-1
a、如果C-1是偶数,下一轮就追上了
b、如果C-1是偶数,那么永远追不上当速度差为偶数,N是奇数,C-1为奇数只有这种情况就会死循环永远也追不上!!!
三.题目练习
题目一.判断是否为环形链表
套用模板想当简单
题目二.返回环形链表的初始结点
注意中里不仅要判断是否为带环链表还必须返回开始结点
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode *detectCycle(struct ListNode *head)
{
if(head==NULL||head->next==NULL)
{
return NULL;
}
struct ListNode *fast=head;
struct ListNode *slow=head;
while(fast&&fast->next)
{
fast=fast->next->next;
slow=slow->next;
if(fast==slow)
{
fast=head;
while(1)
{
if(fast==slow)
{
return fast;
}
fast=fast->next;
slow=slow->next;
}
}
}
return NULL;
}
由于个人精力,能力有限 ,如有错误欢迎指出!!!!
小bit!!!