题目如下:
原题链接: 环形链表II——力扣
分析:对于这个题目我们首先要判断这个链表是不是有环,然后再去找到环的入口
📝我们上文提到:如果定义两个对结点的引用变量fast和slow,他们一开始都分别指向头结点。但不同的是fast每次移动两个结点,slow每次移动一个结点。他们如果相遇就说明这个链表一定有环然后如果有环的话, 就要找到环的入口结点。
我们知道当fast和slow所对应的结点相遇时,fast一定是比slow要多走了几个环的长度的(也正是这几个环的长度抵消了fast比slow每一步所多走的结点数)
那么现在对整个链表来说,有这么几个点是需要我们关注的:环的入口结点、fast和slow的相遇结点。那么我们就可以画出这样的图:
📝那么当fast和slow相遇时 :slow走了:x+y个结点,fast走了:x+y+n(y+z)个结点,其中y+z是环的长度,此时相当于fast比slow多走了n个环的长度(n>=1,n至少为1,要不然快慢指针也不可能相遇)。
我们知道fast一次走两个结点、slow一次走一个结点,同时fast和slow走的次数是相同的,所以说fast走的结点数就是slow走的结点数的两倍
即:n(y+z) == x + y,我们要求的是x的长度(环的入口结点),那么上式就可以写成
x = (n-1)(y+z) + z(n >= 1)
🍑当n等于1时,即x==z,从图上我们可以想象一下如果此时一个结点index1从相遇结点开始走,另一个结点index2从头结点开始走,每次他们两个走相同的结点数,那么他们不就会在环的入口结点相遇吗?
🍑当n大于1时候,即x = z + 几个环的长度 ,此时无非就是相当于从相遇结点出发的index1绕着环多走了几圈,然后才和从头结点出发的index2相遇。此时index2走了x个长度,index1走了z+几个环的长度。
🌰 代码如下:
public class Solution { public ListNode detectCycle(ListNode head) { if (head == null || head.next == null) return null; // 如果在链表只有一个结点或者没有结点,一定为无环 ListNode fast = head, slow = head; while (fast != null && fast.next != null) { slow = slow.next; fast = fast.next.next; if (slow == fast) break; // 快慢指针相遇:说明有环 } if (fast == null) return null; // 如果是因为fast == null 退出循环的话,说明无环 else { // 一个结点index1从相遇结点开始走,另一个结点index2从头结点开始走 ListNode index1 = slow, index2 = head; while (index1 != null && index2 != null) { if (index1 == index2) break; // if要放在前面,处理当入环的结点是0的这种情况 index1 = index1.next; index2 = index2.next; } return index1; // 他们两个结点的相遇处,就是环的入口 } } }
运行结果