141. 环形链表
给定一个链表,判断链表中是否有环。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:true
解释:链表中有一个环,其尾部连接到第二个节点。
示例 2:
输入:head = [1,2], pos = 0
输出:true
解释:链表中有一个环,其尾部连接到第一个节点。
示例 3:
输入:head = [1], pos = -1
输出:false
解释:链表中没有环。
-
1.set集合法
思路:
1.遍历该链表,将每个节点都放入set集合中
2.如果是环形链表在遍历过程中一定存在相同的节点,反之则不是环形链表
public static class ListNode {
private int val;
private ListNode next;
public ListNode(int val) {
this.val = val;
}
}
public boolean hasCycle(ListNode head) {
Set<ListNode> set = new HashSet<>();
while (head != null) {
if (set.contains(head)) {
return true;
} else {
set.add(head);
head = head.next;
}
}
return false;
}
复杂度分析:
时间复杂度:O(n),对于含有 n 个元素的链表,我们访问每个元素最多一次。添加一个结点到哈希表中只需要花费 O(1) 的时间。
空间复杂度:O(n),空间取决于添加到哈希表中的元素数目,最多可以添加 n 个元素。
-
2.双指针法
思路:
1.初始化两个指针 slow = head 、fast = head.next,
2.遍历链表,slow = slow.next,fast = fast.next.next
3.如果是环形链表的话,一定存在 slow = fast, 否则不是环形链表
public boolean hasCycle(ListNode head) {
if (head == null || head.next == null) return false;
ListNode slow = head;
ListNode fast = head.next;
while (fast != null && fast.next != null) {
if (fast == slow) return true;
slow = slow.next;
fast = fast.next.next;
}
return false;
}
复杂度分析:
时间复杂度:O(n)
空间复杂度:O(1),由于只使用了两个指针,空间复杂度为O(1)
-
3.双指针法
思路:
同上
public boolean hasCycle(ListNode head) {
if (head == null || head.next == null) return false;
ListNode slow = head;
ListNode fast = head.next;
while (slow != fast) {
if (fast == null || fast.next == null) return false;
slow = slow.next;
fast = fast.next.next;
}
return true;
}
复杂度分析:
时间复杂度:O(n)
空间复杂度:O(1),由于只使用了两个指针,空间复杂度为O(1)
-
源码
-
我会随时更新新的算法,并尽可能尝试不同解法,如果发现问题请指正
- Github