判断链表是否有环,求环的入口点及环长

今天的内容主要包括三部分,RT。

1。判断链表是否带环

判断链表是否带环,我们可以采用在头结点设两个指针,一个叫fast,一个叫slow,fast一下走两步,而slow一下走一步。如果链表中存在环的话,那么fast和slow必定会在环中相遇。若链表中没有环的话,那么fast必定现于slow指针先到达链表的尾节点(->next = Null)。我们现在来思考一个问题,为什么链表中存在环,则slow和fast会在环中相遇?这个道理,我们可以联想我们跑步追赶的例子,跑道是前面一段直行路,

后面是一个圆圈,当跑步选手进入环形跑道之后就只能在环形跑道里面继续奔跑。有两名选手在起点同时出发,那么我们很容易明白跑得快的选手肯定会追赶上跑的慢的选手。哎,生活中都是学问啊,有木有???

2. 求环的入口点

老实说,求环的入口点有点复杂。我也是在看了一些前辈们的文章才比较清楚到底是怎么一回事(http://www.cnblogs.com/youxin/p/3303172.html)。我们先看一幅图,这幅图也是我在程序中构造带环链表的原型。


如上图所示,12为带环链表的入口点,简单分析可知243是fast和slow的相遇点(鹊桥相会啊==!),a为环入口点到头结点的路程,x为相遇点到环入口点的路程。我们假设slow指针走过的路程为s,那么fast指针走过的路程则为2s,假设环长为c。且有

2s = s + nc

s = a + x

有上述式子,我们可以得到

a + x = nc

a = nc – x

a = (n – 1)c + c -x

式子化来化去,到这儿,我们是不是感觉有点不对经,好想如果在头结点位置和相遇点位置分别再派出两名跑步选手,并且他们都每次只跑一步,好像会在环的入口点相遇啊!!!恭喜你,答对啦!具体原因我们再分析分析最后一个式子就能明白了。啊。。。。求个环的入口点,我容易嘛我??

3.求环长

求环长就比较容易啦,没用到什么数学知识,对于数学知识捉急的我真是终于松了一口气。就是再环的入口点设一指针和一计数器,让这一指针在环里面跑,计数器不断自增。当这一指针回到环的入口点的时候,环长就出来啦!

4.完整代码请见:

http://www.anycodex.com/blog/?p=97

5.测试平台www.anycodex.com


明天的任务是求两链表是否相交,在链表存在有环的情况。继续努力,机会只留给有准备的人!!!

### 快慢指针算法判断链表是否 快慢指针是一种经典的算法思想,用于检测单链表是否存在。其核心原理基于两个指针在链表中的移动速度差异。以下是快慢指针算法的详细说明: #### 算法原理 1. **无情况**:如果链表中不存在,则快指针最终会到达链表末尾(即 `NULL` 或 `None`)。此时,可以确定链表[^1]。 2. **有情况**:如果链表中存在,则快指针和慢指针会在某一时刻相遇。这是因为快指针的速度是慢指针的两倍,因此快指针一定会从后面追上慢指针与其相遇[^2]。 #### 为什么快慢指针一定会相遇? - 在有的情况下,快指针和慢指针进入后,快指针以每次两步的速度前进,而慢指针以每次一步的速度前进。由于的存在,快指针不会超出链表范围,而是不断追赶慢指针。根据数学推导,快指针和慢指针一定会在内的某个节相遇[^3]。 #### 代码实现 以下是一个使用快慢指针检测链表是否的代码示例: ```java public class Solution { public boolean hasCycle(ListNode head) { if (head == null || head.next == null) { return false; // 如果链表为空或只有一个节且无后续节,则无 } ListNode slow = head; // 慢指针初始化为头节 ListNode fast = head; // 快指针初始化为头节 while (fast != null && fast.next != null) { slow = slow.next; // 慢指针每次移动一步 fast = fast.next.next; // 快指针每次移动两步 if (slow == fast) { // 如果快慢指针相遇,则链表 return true; } } return false; // 如果快指针到达链表末尾,则链表 } } ``` #### 找到的起 如果需要找到入口,可以在快慢指针相遇后,将一个指针重新指向链表头部,然后两个指针以相同速度(每次一步)前进。它们再次相遇的节即为入口[^3]。 ```java public ListNode detectCycle(ListNode head) { ListNode slow = head; ListNode fast = head; boolean hasCycle = false; while (fast != null && fast.next != null) { slow = slow.next; fast = fast.next.next; if (slow == fast) { hasCycle = true; break; } } if (!hasCycle) { return null; // 如果没有,返回 null } slow = head; // 将慢指针重置到链表头部 while (slow != fast) { slow = slow.next; fast = fast.next; } return slow; // 返回入口 } ``` ### 注意事项 - 快慢指针算法的时间复杂度为 \(O(n)\),空间复杂度为 \(O(1)\),非常适合用于判断链表是否。 - 在实现时,需注意边界条件,例如链表为空或只有一个节的情况。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值