如何判断链表有环
给一个单向链表,使用程序来判断链表中是否存在环结构。
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
| private static class Node { int data; Node next;
Node(int data) { this.data = data; } }
public static void main(String[] args) { 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(isCycle1(node1)); System.out.println(isCycle2(node1)); System.out.println(isCycle3(node1)); }
|
解法一
解法一:依次遍历链表的节点,每遍历一个节点,就从头部开始检查到当前节点之前的所有节点,用当前节点和此节点之前的所有节点进行比较,如果存在相等的节点,则说明链表结构存在环,否则继续遍历节点,直到链表结束。
代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| private static boolean isCycle1(Node head) { Node currentNode = head.next; int currentIndex = 1; while (currentNode != null) { Node node = head; int i = 0; while (node != null && i < currentIndex) { if (node == currentNode) { return true; } node = node.next; i++; } currentNode = currentNode.next; currentIndex++; } return false; }
|
解法二
解法二:使用一个 HashSet 结构,从头开始遍历链表,每次遍历连接,使用当前节点去 HashSet 中获取节点元素,如果 HashSet 中不存在当前节点,则将当前节点存入 HashSet 容器中,如果 HashSet 中存在当前节点,说明链表存在环。
这其实是一种类似 Redis 中的布隆过滤器的结构。
代码实现:
1 2 3 4 5 6 7 8 9 10 11
| private static boolean isCycle2(Node head) { Set<Node> set = new HashSet<>(); while (head != null) { if (set.remove(head)) { return true; } set.add(head); head = head.next; } return false; }
|
解法三
解法三:使用两个指针,让它们从头部开始遍历,其中一个指针每次遍历向后移动一个节点,另一个指针每次遍历向后移动两个节点,然后比较两个指针指向的节点是否相同。如果相同,则可以判断出链表有换,如果不同,则继续下一次循环。
代码实现:
1 2 3 4 5 6 7 8 9 10 11 12
| private static boolean isCycle3(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; }
|
解法评估
- |
解法一 |
解法二 |
解法三 |
时间复杂度 |
O(n^2) |
O(n) |
O(n) |
空间复杂度 |
O(1) |
O(n) |
O(1) |
最后
本文Github https://github.com/herenpeng/code-learn 已收录,欢迎Star。