问题描述
怎么能够更高效地判断一个链表是否有环?
首先创建两个指针p1和p2(在Java里就是两个对象引用),让它们同时指向这个链表的头节点。
然后开始一个大循环,在循环体中,让指针p1每次向后移动1个节点,让指针p2每次向后移动2个节点,然后比较两个指针指向的节点是否相同。如果相同,则可以判断出链表有环,如果不同,则继续下一次循环。
复杂度分析
假设链表的节点数量为n,则该算法的时间复杂度为O(n)。
除两个指针外,没有使用任何额外的存储空间,所以空间复杂度是O(1)
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| public class LinkedListCycle {
public static boolean isCycle(Node head) { Node p1 = head; Node p2 = head; while (p2!=null && p2.next!=null){ p1 = p1.next; p2 = p2.next.next; if(p1 == p2){ return true; } } return false; }
private static class Node { int data; Node next; Node(int data) { this.data = data; } }
public static void main(String[] args) throws Exception { Node node1 = new Node(5); Node node2 = new Node(3); Node node3 = new Node(7); Node node4 = new Node(2); Node node5 = new Node(6); node1.next = node2; node2.next = node3; node3.next = node4; node4.next = node5; node5.next = node2;
System.out.println(isCycle(node1)); } }
|
扩展
如果链表有环,如何求出环的长?
当两个指针首次相遇,证明链表有环的时候,让两个指针从相遇点继续循环前进,并统计前进的循环次数,直到两个指针第2次相遇。此时,统计出来的前进次数就是环长。
因为指针p1每次走1步,指针p2每次走2步,两者的速度差是1步。当两个指针再次相遇时,p2比p1多走了整整1圈因此,环长 = 每一次速度差 × 前进次数 = 前进次数
参考文献
https://www.cnblogs.com/zhaoqingqing/p/11853924.html