前言:内容包括-题目,代码实现,大致思路,代码解读,拓展问题
题目:
给你一个链表的头节点 head ,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos 不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true 。 否则,返回 false 。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/linked-list-cycle
代码实现:
bool hasCycle(struct ListNode *head)
{
struct ListNode *slow = head;
struct ListNode *fast = head;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(slow == fast)
{
return true;
}
}
return false;
}
大致思路:
1 使用快慢指针遍历链表,slow一次走一步,fast一次走两步,若是遍历能够结束则不是环形链表
注意:链表结点的个数可为偶数,奇数
若是偶数个结点,遍历结束的条件是fast为NULL
若是奇数个结点,遍历结束的条件是fast->next为NULL
2 若是循环不能结束
fast指针会先进入环形中,slow指针后进入环形中
当slow指针进入环形后,fast开始追击slow,两个人每行动一次,它们之间的距离会缩小1
所以fast一定会追上slow,即fast和slow会相遇,这便是有环形链表存在的有利证明
因为若是没有环形链表,则fast和slow永不会相遇,而正是有了环形链表,fast和slow才会相遇
代码解读:
bool hasCycle(struct ListNode *head)
{
struct ListNode *slow = head;
struct ListNode *fast = head;
while(fast && fast->next)//遍历链表
{
slow = slow->next;//slow一次走一步
fast = fast->next->next;//fast一次走两步
if(slow == fast)//存在环形链表,使原本不会相遇的fast和slow会面
{
return true;
}
}
return false;//遍历能够结束,不存在环形链表
}
拓展问题:
1 slow和fast一定会相遇吗?
答:一定会相遇
fast会先进环,slow会后进环,假设当slow进环后,fast和slow之间的距离为N
fast开始追击slow,slow一次走一步,fast一次走一步,二者每行动一次,之间的距离缩小1
它们的距离变化如下:
N
N-1
N-2
……
2
1
0
可以看到slow和fast之间的距离最终会缩小至0,即slow和fast相遇了
2 若是slow走一步,fast走3/4/5步,可以相遇吗?
答:不一定相遇
以slow走一步,fast走3步为例
fast会先进环,slow会后进环,假设当slow进环后,fast和slow之间的距离为N
fast开始追击slow,slow一次走一步,fast一次走3步,二者每行动一次,之间的距离缩小2
它们的距离变化如下:
当N为2的倍数(偶数)时
N
N-2
N-4
……
2
0
slow和fast会相遇
当N不是2的倍数(奇数)时
N
N-2
N-4
……
3
1
-1
slow和fast会错过,二者会间隔一步
错过之后进入下一轮追击,fast和slow的距离变成C-1
若是C-1为偶数,slow和fast可以相遇
若是C-1为奇数,slow和fast永远不会相遇