141. Linked List Cycle
Leetcode Linked ListGiven a linked list, determine if it has a cycle in it.
Follow up:
Can you solve it without using extra space?
分析¶
判断链表是否有环。这里使用两种方案:
- 第一种当然最直接,把元素放到hashset中,然后看该元素是否已经包含在hashset中。
- 第二种,需要动一点脑子,
- 两个指针,一直跑,一前一后,前面的跑的快,后面的跑得慢,看快的是否能追上慢的。
- 追的上,说明链表肯定是有循环的。如果跑的快的直接跑到终点了,那就是没循环。
/**
* Use the method of HashSet
* To detect if a list is cyclic,
* we can check whether a node had been visited before.
* A natural way is to use a hash table.
*/
public boolean hasCycle(ListNode head) {
HashSet<ListNode> set = new HashSet<>();
while (head != null) {
if (set.contains(head)) {
return true;
}
set.add(head);
head = head.next;
}
return false;
}
两个指针的方案,想象一下两个运动员在跑道上以不同的速度跑步。如果跑道是个圆,那么将会发生什么?考虑两个不同速度移动的指针 - 慢指针和快指针。如果在链表中没有环,快指针将会跑到终点,我们可以返回false。如果链表中包含环,那么快指针和慢指针最终将相遇。
- 注意要让fast跑在slow前面,这样才能跑完完整一圈
public boolean hasCycle(ListNode head) {
if (head == null || head.next == null) return false;
ListNode slow = head; // 慢指针在后
ListNode fast = head.next; // 快指针在前
while (fast != slow) { // 判断是否相遇
// 快指针跑完了,返回false
if ((fast == null) || (fast.next == null)) return false;
slow = slow.next;
fast = fast.next.next;
}
return true;
}
- 也可以让慢指针和快指针同时从起点开始,但是while循环判断的条件要改变,因为一开始fast = slow.
public boolean hasCycle(ListNode head) {
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (fast == slow) return true;
}
return false;
}