Leetcode刷题笔记之链表篇141. 环形链表
Posted 大家好我叫张同学
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Leetcode刷题笔记之链表篇141. 环形链表相关的知识,希望对你有一定的参考价值。
😈博客主页:🐼大家好我叫张同学🐼
💖 欢迎点赞 👍 收藏 💗留言 📝 欢迎讨论! 👀
🎵本文由 【大家好我叫张同学】 原创,首发于 CSDN 🌟🌟🌟
✨精品专栏(不定时更新) 【数据结构+算法】 【做题笔记】【C语言编程学习】
☀️ 精品文章推荐
【C语言进阶学习笔记】三、字符串函数详解(1)(爆肝吐血整理,建议收藏!!!)
【C语言基础学习笔记】+【C语言进阶学习笔记】总结篇(坚持才有收获!)
前言 |
为什么要写
刷题笔记
?
写博客
的过程也是对自己刷题过程的梳理
和总结
,是一种耗时
但有效
的方法。
当自己分享的博客帮助到他人时,又会给自己带来额外的快乐和幸福。
(刷题的快乐+博客的快乐,简直是奖励翻倍,快乐翻倍
有木有QAQ🙈)
题目内容 |
给你一个链表的头节点
head
,判断链表中是否有环
。 如果链表中有某个节点,可以通过连续跟踪
next
指针再次到达,则链表中存在环。
为了表示给定链表中的环,评测系统内部使用整数pos
来表示链表尾连接到链表中的位置(索引从0
开始)。如果pos
是-1
,则在该链表中没有环。
注意:pos
不作为参数进行传递,仅仅是为了标识链表的实际情况。 如果链表中存在环,则返回true
。 否则,返回false
。
暴力取巧法 |
要解决这个问题,有一个不算方法的方法,我们注意到题目中说了链表中节点的数目范围是[0, 10^4]
。
对于带环的链表,我们去求其长度,一定是大于10^4
的(也就是10000
)。
对于不带环的链表,其长度一定是小于等于10000
的。因此这个地方可以取巧,直接取计算链表的长度,就可以判断是否带环。
函数实现 |
bool hasCycle(struct ListNode *head)
//暴力求解法 如果链表有环,长度计算length会无穷大
struct ListNode* cur = head;
int length = 0;
while(cur && (length < 100001))
cur = cur->next;
length++;
if(cur == NULL)
return false;
else
return true;
虽然这种方法可以求出链表是否带环,但实际中我们最好不要使用
这种方法。
原因如下:
1)这种方式需要事先知道链表的最大长度是多少。
2)当链表长度很大的时候,比如1千万、1个亿结点,这时候程序的效率就会很低。
快慢指针法 |
要判断链表是否带环,一般都采用快慢指针
的方法(快指针
一次走两步
,慢指针
一次走一步
)。若链表不带环,那么快指针
势必会走到最后一个结点或空结点,即fast = NULL
,或 fast->next = NULL
。若链表不带环,那么快指针后面就会一直在环里面走啊走,转啊转,出不去。若while
循环中终止条件是fast == NULL
或 fast->next == NULL
,那么while
循环就无法终止。为了在链表带环时,while
循环还能终止,将条件改为 fast != slow
。若带环,则fast
与slow
必定会在环中相遇。(证明过程在后面)
函数实现 |
bool hasCycle(struct ListNode *head)
if(head == NULL || head->next == NULL)
return false;
struct ListNode* fast = head->next;
struct ListNode* slow = head;
while(fast != slow)
if(fast == NULL || fast->next == NULL)
return false;
fast = fast->next->next;
slow = slow->next;
return true;
当然也可以这样写,这样就不需要利用虚拟结点,fas
t和slow
同时从头结点head
开始往后走。
bool hasCycle(struct ListNode *head)
struct ListNode *fast = head,*slow = head;
while(fast && fast->next)
fast = fast->next->next;
slow = slow->next;
if(fast == slow)
return true;
return false;
带环问题的证明过程 |
1)slow一次走一步,fast一次走两步,一定可以相遇吗?请证明
2)slow一次走一步,fast一次走n步(n >2,n = 3,4,5…),一定可以相遇吗?请证明
问题(1)
答:一定可以追上,证明如下:
①首先我们要理解环的大小、环前面链表部分的长度都是
不确定
的。
②那么当slow
进入环的时候,fast
已经在环里面走了一会了,这时候fast
要和slow
相遇,就需要fast
追上slow
。
③假设slow
进入环的时候,fast
和slow
之间的距离为n
(fast追上slow需要的步数),环的大小为c
,那么n
一定小于c
(如果n == c
或n == 0
,两者就相遇
了)。
④而fast
在追赶slow
的过程中,slow一次走一步,fast一次走两步,则fas
t和slow
之间的距离就会减少1
,最终n变为0
,所以fast一定可以追上slow。
⑤slow
进入环里面后,一圈之内
,fast
一定会追上slow
,也就是fast
不会错过slow
。
问题(2)
答:不一定可以追上,证明如下:
①假设slow一次走一步,fast一次走三步,slow进环时,它们之间的差距为n,环的长度为c。
②fast
在追赶slow
的过程中,slow一次走一步,fast一次走三步,则fas
t和slow
之间的距离就会减少2
。也就是说距离会变成n-2、n-4、n-6....
,当n为偶数
的时候,fast就一定
可以追上slow
,当n为奇数
的时候,且c - 1
也为奇数时,fast就永远追不上slow
,一直错过
。
③n
为奇数的时候,n-2、n-4、n-6....
最后变为-1
,-1
就是表示fast
与slow
相差-1
步,也就是c-1
步。当c-1
为偶数,那么fast
还是可以追上slow
。当c-1
为奇数,fast
永远追不上slow
。
以上是关于Leetcode刷题笔记之链表篇141. 环形链表的主要内容,如果未能解决你的问题,请参考以下文章