本篇文章将是单向链表的最后一篇文章,也是最后一题,难度较大,大家注意细品~这篇文章结束后,我们将进入双向链表的学习,话不多说,进入正题叭~
上一篇文章中,我们介绍了有关环的两道例题,这篇文章中,我们将继续介绍环的问题,敬请期待吧~
1.给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 NULL
我们先借助图片来理解
如图,题目要求的,就是上方图片的入口点 ,
思路:让一个指针从链表起始位置开始遍历链表,同时让一个指针从判环时相遇点的位置开始绕环运行,两个指针都是每次均走一步,最终肯定会在入口点的位置相遇
当然,只有结论是远远不够的,我们要一步一步推导,得到上面的结论
我们还是先定义快慢两个引用 fast,slow
我们先讨论最好情况,这里请大家思考一下, 如果两个引用要相遇,最好的情况下,就是fast已经走完一圈,fast和slow才会在环里相遇,不可能说慢的在快的还没走到环里时,可以追上快的不是
下面我们做具体分析
起始点到入口点的距离为:X
环的长度为:C
相遇点到入口点的距离为:Y
如图
最快时间相遇
fast的路程:X+C(C-Y)
slow的路程:X+(C-Y)
又因为fast速度是slow的2倍:X+(C-Y)= 2(X+C(C-Y))
化简后为:X=Y
这里假设fast的已经在圈里跑n圈了,slow才和fast相遇,这里可以理解为起始点到入口点距离很长,环非常小
fast的路程:X+nC(C-Y)( 这里假设fast的已经在圈里跑n圈了,slow才和fast相遇)
slow的路程:X+(C-Y)
又因为fast速度是slow的2倍:X+nC(C-Y)= 2(X+C(C-Y))
化简后为:X=(n-1)Y
此时n = 1时,就是咱们上面推导的公式
代码如下
这里我们要先判断是否有环这个方法咋爱上一篇文章中已经详细讲过,这里修改返回值,在编写新代码即可
public ListNode detectCycle() {
if(head == null) return null;
ListNode fast = head;
ListNode slow = head;
while(fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
if(fast == slow) {
break;
}
}
if(fast == null || fast.next == null) {
//没环
return null;
}
//此时相遇,fast,slow每次走一步
fast = head;
while(fast != slow) {
fast = fast.next;
slow = slow.next;
}
return fast;
}
调用测试
这里我们还是老样子,手动创环,调用方法,在进行判断
private static void createIntersect(MySingleList.ListNode headA,
MySingleList.ListNode headB) {
headB.next.next = headA.next.next;
}
public static void main(String[] args) {
MySingleList mySingleList = new MySingleList();
mySingleList.addLast(12);
mySingleList.addLast(23);
mySingleList.addLast(34);
mySingleList.addLast(45);
mySingleList.addLast(56);
mySingleList.display();
mySingleList.createLoop();
System.out.println(mySingleList.hasCycle());
MySingleList.ListNode ret = mySingleList.detectCycle();
System.out.println(ret.val);
}
运行借图
到此为止,我们的单向链表的学习就到此结束啦~明天我们将进入双向链表的学习,敬请期待叭·~
觉得up主讲得还可以的各位观众朋友可以来个三连~谢谢大家~我们下期再见~