一 问题
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:首先从头节点开始,依次遍历单链表的每一个节点。每遍历到一个新节点,就从头节点重新遍历新节点之前的所有节点,用新节点ID和此节点之前所有节点ID依次作比较。如果发现新节点之前的所有节点当中存在相同节点ID,则说明该节点被遍历过两次,链表有环;否则继续下一个节点。
这个时间复杂度很高,O(MN)。
思路2:为了提高效率,使用HashSet作为额外的缓存。创建一个以节点ID为键的HashSet集合,用来存储曾经遍历过的节点。然后同样是从头节点开始,依次遍历单链表的每一个节点。判断hashset是否存在,则说明链表有环,如果HashSet当中不存在相同的节点ID,就把这个新节点ID存入HashSet,之后进入下一节点。
时间复杂度O(N),使用了额外的空间。
怎么样实现时间复杂度最优且空间复杂度O(1)呢?我也没想到,看了大神的文章。
思路3: 快慢指针法。即采用两个指针slow和fast,slow每次移动一步而fast每次移动两步。当slow和fast相遇时,证明链表有环
//快慢指针
public boolean hasCycle(ListNode head) {
//conner case
if(head == null|| head.next == null){
return false;
}
ListNode slow = head;
ListNode fast = head;
while(slow.next!= null && fast.next.next!= null){
slow =slow.next;
fast = fast.next.next;
if(slow == fast){
return true;
}
}
return false;
}
Runtime: 0 ms, faster than 100.00% of Java online submissions for Linked List Cycle.
Memory Usage: 37.3 MB, less than 100.00% of Java online submissions forLinked List Cycle.