【算法】判断链表是否有环/环入口点/…
题目
这是一个比较经典的问题,给定一个单链表,判断其中是否有环
其他相关算法:
- 如果存在环,找出环的入口点
- 如果存在环,求出环上节点的个数
一、判断其中是否有环
思路
快慢指针:开始的时候两个指针都指向链表头,然后让快指针fast向后移动两个节点,同时慢指针slow向后移动一个节点,直到快指针指向null为止。
由于fast要比slow移动的快,如果有环,fast一定会先进入环,而slow后进入环。当两个指针都进入环之后,经过一定步的操作之后,二者一定能够在环上相遇,并且此时slow还没有绕环一圈,也就是说一定是在slow走完第一圈之前相遇。
代码
public static boolean hasCircle(ListNode head) {
//慢指针、快指针都指向链表头
ListNode slow = head;
ListNode fast = head;
// 快指针fast向后移动两个节点,同时慢指针slow向后移动一个节点,直到快指针指向null为止
while (fast != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
// 说明有环
return true;
}
}
// 说明无环
return false;
}
class ListNode {
int val;
ListNode next;
ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
二、如果存在环,找出环的入口点
思路
基于一的步骤,先找到快慢指针的相遇点,此时让慢指针仍指向该相遇点,快指针重新指向链表头节点,然后快慢保持同一的速度遍历,直到下次两个指针再次相遇,此时就是链表的环形入口。
代码
public ListNode getEnterNode(ListNode head) {
//慢指针、快指针都指向链表头
ListNode slow = head;
ListNode fast = head;
// 快指针fast向后移动两个节点,同时慢指针slow向后移动一个节点,直到快指针指向null为止
while (fast != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
// 说明有环,且此时slow指针在相遇点处
break;
}
}
fast = head;
// 快慢保持同一的速度遍历,直到下次两个指针再次相遇(或者快指针指向null为止)
while (fast != null) {
fast = fast.next;
slow = slow.next;
if (fast == slow) {
// 相遇点就是链表的环形入口
return fast;
}
}
return null;
}