判断链表成环,且找出环的起点。
- 判断链表成环
- 找出环的起点
- Java代码实现
1. 判断链表是否成环
Floyd环判断法:从同一个起点同时开始以不同速度前进的2个指针最终相遇,那么可以判定存在一个环。
设想:乌龟和兔子在同一个环上赛跑,跑的快的兔子速度为2,跑的慢的乌龟速度为1,则兔子终会赶上乌龟。
理解:如果以乌龟为参考对象,则兔子前进的速度为1,这就意味着,兔子必将赶上乌龟。
所以一个判断成环的方法是:先舍子两个指针都指向表头,其中p1每次前进一个节点,p2每次前进两个节点,且p1和p2同时走,当p2指向的地址为null,就证明链表没有环。如果在某个时刻,p1和p2指向的地址相同,那么链表就是有环的。
2.找出环的起点
同时可以进一步考虑:K1是等于零的,也就是p1在进入环后,走了不到一圈就在交点处和p2重合。因为p1在进入环的时候,p2和p1之间的距离(沿着行走方向)至多为 d2-1,不可能超过d2-1,因为环的大小也才只有d2 。p2追赶p1,最多只需要走d2-1步,因为每走一步,p1和p2的相对距离减小1,那么p1最多只走了d2-1步,就是最多只经过了d2-1个节点,不可能走完一圈。
最后推出的式子的含义可以理解为:d1的长度 = 环长度的整数倍 + 交点与环入口的距离
所以我们可以得出:当p1和p2相遇后,让p1回到原点,p2在相遇点,且两者每次都前进一个节点,当两者再次相遇时,就是环的起点。
3. Java代码实现
int FindBeginLoop(ListNode head){
ListNode p1 = head, p2 = head;
boolean loopExists = false;
if(head == null)
return false;
//判断环是否存在
while(p2.getNext()!=null&&p2.getNext().getNext()!=null){
p1 = p1.getNext();
p2 = p2.getNext().getNext();
if(p1==p2)
loopExists = true;
break;
}
//如果环存在,寻找环的起点
if(loopExists){
p1 = head;
while(p1!=p2){
p1 = p1.getNext();
p2 = p2.getNext();
}
return p1;
}
return null; //不存在
}
//附:定义的LitNode类
public class ListNode {
private int data;
private ListNode next;
public ListNode(int data) {
this.data = data;
}
public int getData() {
return data;
}
public void setData(int data) {
this.data = data;
}
public SingleListNode getNext() {
return next;
}
public void setNext(SingleListNode next) {
this.next = next;
}
}