题目:给你一个单链表链表,判定该链表是否存在循环链表于其中
我开始是想通过遍历,如果没有next域为空肯定是循环链表,但是问题是我跟本不知链表的终点,又想了一些其他的方法都没有可行性,又不想用双重循环来判定
后来找到了下面的方法,利用快慢指针,如果是循环的链表,二者肯定会在某一点相遇,代码如下
public boolean hasCycle(ListNode head) {
if(head==null) return false;
ListNode walker = head;
ListNode runner = head;
while(runner.next!=null && runner.next.next!=null) {
walker = walker.next;
runner = runner.next.next;
if(walker==runner) return true;
}
return false;
}
升级版是寻找到循环起点:下面是别人的分析
假设刚进环的时候慢指针走了m步,环的大小为n,快慢指针在距离环起点x步的时候相遇。慢指针是一定走不完一圈就会和快指针相遇的(因为最惨的情况下就是慢指针进圈的时候快指针在它前面一个,快指针速度时慢的两倍,这种悲剧情况下慢指针也不可能走完一圈就会被追到)。这是慢指针走了m+x步,快指针走了2(m+x)步,快指针在圈内走了2(m+x)-m=m+2x步。由于相遇在x位置,所以 m+2x % n = x,推出m+2x = i * n + x,于是m+x = i*n。我们注意到慢指针已经走了x步了,再走m步时一定会回到圈的起点的(m+x = i*n),所以等它们相遇后,一个指针从head开始走,然后慢指针从相遇的位置出发,则一定会相遇到圈的起点
public ListNode detectCycle(ListNode head) {
ListNode p1 = head;
ListNode p2 = head;
while(p2 != null && p2.next != null){
p1 = p1.next;
p2 = p2.next.next;
if (p1 == p2) break;
}
if (p2 == null || p2.next == null){
return null;
}
p1 = head;
while(p1 != p2){
p1 = p1.next;
p2 = p2.next;
}
return p2;
}