1.判断一个链表有没有环
这个题目很经典,剑指offer和leetcode141上都有原题,核心思想就是快慢指针,当两个指针相遇的时候说明是有环的。代码如下:
public boolean hasCycle(ListNode head) {
if (head == null || head.next == null)
return false;
ListNode slow = head, fast = head;
while(fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) { //两者相遇了
return true;
}
}
return false;
}
2. 找到环的入口
这一步骤是根据上面那一步得到的答案,当两个指针相遇的时候说明链表是有环的。此时如果要找到这个环的入口的话,那就需要三步:
- 记住两个指针相遇的节点,为p1。
- 然后初始化p2从链表开始,让p1和p2以速度为1的方式向前走
- 当两者相遇时,就是环的入口。
代码如下:
public ListNode detectCycle(ListNode head) {
if (head == null || head.next == null)
return null;
ListNode slow = head, fast = head;
while(fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if(fast == slow) {
break; //和上面基本一样,只是相遇的时候记录并退出循环
}
}
if(fast == null || fast.next == null) //如果是因为fast的原因,说明无环
return null;
ListNode p2 = head; //从head开始,两者一起走,直到相遇
while(p2 != fast) {
p2 = p2.next;
fast = fast.next;
}
return p2;
}
3. 得到环的长度
这个就依赖于第2步中所得到的的入口,然后一个节点去环里面走,直到出口位置就可以得到了。
当然也可以在两个节点第一次相遇时,然后继续维持自己的步伐,直到第二次相遇就得到了环的长度。