说明
算法:Linked List Cycle
LeetCode地址:https://leetcode.com/problems/linked-list-cycle/
题目:
Given a linked list, determine if it has a cycle in it.
To represent a cycle in the given linked list, we use an integer pos which represents the position (0-indexed) in the linked list where tail connects to. If pos is -1, then there is no cycle in the linked list.
Example 1:
Input: head = [3,2,0,-4], pos = 1
Output: true
Explanation: There is a cycle in the linked list, where tail connects to the second node.
Example 2:
Input: head = [1,2], pos = 0
Output: true
Explanation: There is a cycle in the linked list, where tail connects to the first node.
Example 3:
Input: head = [1], pos = -1
Output: false
Explanation: There is no cycle in the linked list.
Follow up:
Can you solve it using O(1) (i.e. constant) memory?
解题思路1
环形链表只要判断是否经过相同的对象,用到去重容器Set来存储已经遍历的数据,遍历链表,判断是否存在于Set中。因为需要Set容器,空间复杂度为O(n), 时间复杂度为O(n).
代码实现1
import java.util.HashSet;
import java.util.Set;
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
}
public class LinkedListCycle {
public boolean hasCycle(ListNode head) {
Set<Integer> pastSet = new HashSet<>();
while (head != null) {
if (pastSet.contains(head.val)) {
return true;
} else {
pastSet.add(head.val);
head = head.next;
}
}
return false;
}
}
代码执行效率1
Runtime: 6 ms, faster than 11.95% of Java online submissions for Linked List Cycle.
Memory Usage: 35.4 MB, less than 99.35% of Java online submissions for Linked List Cycle.
解题思路2
题目要求是内存复杂度在O(1), 也就是不能用Set容器。需要用指针的方法处理:
用两个步长分别为slowStep = 1,和fastStep = 2的指针,如果能遍历到下个结点是null,说明不是循环列表. 循环列表里面,两个步长的相差为1,肯定会相遇。
证明:异常情况:两个步长不相遇的情况,只有一种可能,步长1在步长2的节点前面相差1. 循环区间的长度为K,那么K有两种情况,要么是奇数,要么是偶数。
先假设遍历的位置,slowIndex = 1, fastIndex = 0;(实际上slowIndex = 2, fastIndex = 1也是相同的证明方法)
-
K == 奇数:fastStep到终点,slowIndex = 1 + ½ * (k - 1) , fastIndex = k - 2; 再走步数 ½ * (k - 1) , slowIndex = k, 也就是 slowIndex = 0, fastIndex = k - 1; 下一步 slowIndex == fastIndex == 1.
-
K == 偶数:fastStep到终点,slowIndex = 1 + ½ * k , fastIndex = k - 1; 再走步数½ * k,slowIndex = 1 + k, 相当于 slowIndex = 1 , fastIndex = k, 相当于 fastIndex = 0; 下一步 slowIndex == fastIndex == 1.
空间复杂度为O(1); 时间复杂度为 O(n) , 因为循环区间次数假设为k,实为O(n+k).
代码实现2
public class LinkedListCycle {
public boolean hasCycleWithTwoPoint(ListNode head) {
if (head == null || head.next == null) {
return false;
}
ListNode slowNode = head;
ListNode fastNode = head.next;
while (slowNode != fastNode) {
if (slowNode == null || fastNode == null || fastNode.next == null) {
return false;
}
slowNode = slowNode.next;
fastNode = fastNode.next.next;
}
return true;
}
}
代码执行效率2
Runtime: 0 ms, faster than 100.00% of Java online submissions for Linked List Cycle.
Memory Usage: 39.6 MB, less than 5.15% of Java online submissions for Linked List Cycle.
总结
考查循环链表,和空间复杂度的优化。