题目描述
原题链接
给你一个链表的头节点 head
,判断链表中是否有环。
如果链表中有某个节点,可以通过连续跟踪 next
指针再次到达,则链表中存在环。 为了表示给定链表中的环,评测系统内部使用整数 pos
来表示链表尾连接到链表中的位置(索引从 0 开始)。注意:pos
不作为参数进行传递 。仅仅是为了标识链表的实际情况。
如果链表中存在环 ,则返回 true
。 否则,返回 false
。
成绩
快慢指针
哈希表
解题思路
快慢指针
慢指针每次走一步,快指针每次走两步,如果链表存在环,那么快慢指针一定会相遇。
就像两个人在环形跑道上跑步,一个跑的快,一个跑的慢,那么经过一定时间,两人一定会相遇。
图解如下:
哈希表
遍历链表,每遍历到一个非 null
节点,就将其存入哈希表中,如果哈希表中已经存有当前节点,说明链表存在环,当前节点就是环的入口;如果遍历到 null
,说明链表中不存在环。
图解如下:
代码实现
快慢指针
public class Solution {
public boolean hasCycle(ListNode head) {
if (head == null) {
return false;
}
ListNode fast = head;
ListNode slow = head;
while(fast.next != null && fast.next.next != null) {
fast = fast.next.next;
slow = slow.next;
if(fast == slow) {
return true;
}
}
return false;
}
}
哈希表
public class Solution {
public boolean hasCycle(ListNode head) {
ListNode currentNode = head;
HashSet<ListNode> hash = new HashSet<>();
while(currentNode != null) {
if (hash.contains(currentNode)) {
return true;
}
hash.add(currentNode);
currentNode = currentNode.next;
}
return false;
}
}
优化哈希表
将 HashSet
替换为 HashMap
,key
为当前节点,value
全部存储 null
。这样可以减少内存占用,内存占用的成绩由 83.1% 提升到 94.40%。原因是 HashSet
底层 new 了 HashMap
,元素存储在 HashMap
的 key
,value
存储了一个PRESENT
中,这是一个 Object
对象,会额外占用内存。源码如下:
优化后的代码及效果:
public class Solution {
public boolean hasCycle(ListNode head) {
ListNode currentNode = head;
Map<ListNode, Object> hash = new HashMap<>();
while(currentNode != null) {
if (hash.containsKey(currentNode)) {
return true;
}
hash.put(currentNode, null);
currentNode = currentNode.next;
}
return false;
}
}