【LeetCode题解】141_环形链表
141_环形链表
描述
给定一个链表,判断链表中是否有环。
进阶:
你能否不使用额外空间解决此题?
解法一:哈希表
思路
判断一个链表是否包含环,可以转化为判断是否有一个节点之前已经出现过。非常自然的一个想法就是:遍历链表的每个节点,用一个哈希表记录每个节点的引用(或内存地址);如果能够遍历到空节点,则此时已经遍历到链表的尾部,返回 false;如果有一个节点的引用出现在哈希表中,则返回 true。
Java 实现
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
Set<ListNode> nodesSeen = new HashSet<>();
while (head != null) {
if (nodesSeen.contains(head)) {
return true;
}
nodesSeen.add(head);
head = head.next;
}
return false;
}
}
复杂度分析:
- 时间复杂度:\(O(n)\),其中 \(n\) 为链表的节点数,因为哈希表的查找和添加操作的时间复杂度是 \(O(1)\) 的,所以整体的时间复杂度是 \(O(n)\) 的
- 空间复杂度:\(O(n)\),最多只需要保存 \(n\) 个节点的引用
Python 实现
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def hasCycle(self, head):
"""
:type head: ListNode
:rtype: bool
"""
nodes_seen = set()
while head is not None:
if head in nodes_seen:
return True
nodes_seen.add(head)
head = head.next
return False
复杂度分析同上。
解法二:双指针(龟兔算法)
思路
另一种思路就是采用 Floyd 的龟兔算法,即借用两个指针,一个快指针和一个慢指针,快指针每次移动两个节点而慢指针则每次移动一个节点。如果链表中不存在环,则快指针会先于慢指针到达链表的尾部,两个指针永远也不可能“相遇”;相反,如果链表中存在环,则快指针一定会“追上”慢指针,就如同龟兔赛跑一样,速度快的兔子一定会追上乌龟。
Java 实现
/**
* Definition for singly-linked list.
* class ListNode {
* int val;
* ListNode next;
* ListNode(int x) {
* val = x;
* next = null;
* }
* }
*/
public class Solution {
public boolean hasCycle(ListNode head) {
if (head == null || head.next == null) {
return false;
}
ListNode slow = head;
ListNode fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
if (slow == fast) {
return true;
}
}
return false;
}
}
复杂度分析:
时间复杂度:\(O(n)\),其中 \(n\) 为链表的节点数,按照链表中是否存在环,分两种情况进行讨论:
- 链表中不存在环:快指针会优先到达链表尾部(最多只需要 \(n/2\) 次),时间复杂度为 \(O(n)\)
- 链表中存在环:我们可以把慢指针的移动分解成两个部分,“直线“部分和”环形“部分。对于”直线“部分,假设链表中”直线“部分的长度为 \(N\),则慢指针只需 \(N\) 次迭代便可到达”环形“部分,此时快指针已经进入了”环形“部分;对于”环形“部分,假设链表中”环形“部分的长度为 \(K\),由于两个指针的速度之差为 1,因此最坏的情况下,经过 \(K\) 次迭代后快指针便能”追上“慢指针。综上,最坏情况下的时间复杂度为 \(O(N + K) = O(n)\)
空间复杂度:\(O(1)\),只需要存储两个节点的引用
Python 实现
# Definition for singly-linked list.
# class ListNode(object):
# def __init__(self, x):
# self.val = x
# self.next = None
class Solution(object):
def hasCycle(self, head):
"""
:type head: ListNode
:rtype: bool
"""
if head is None or head.next is None:
return False
slow, fast = head, head
while fast is not None and fast.next is not None:
slow, fast = slow.next, fast.next.next
if slow == fast:
return True
return False
# Runtime: 44 ms
# Your runtime beats 95.91 % of python submissions.
复杂度分析同上。
【LeetCode题解】141_环形链表的更多相关文章
- [LeetCode题解]142. 环形链表 II | 快慢指针
解题思路 本题是在141. 环形链表基础上的拓展,如果存在环,要找出环的入口. 如何判断是否存在环,我们知道通过快慢指针,如果相遇就表示有环.那么如何找到入口呢? 如下图所示的链表: 当 fast 与 ...
- [LeetCode题解]141. 环形链表 | 快慢指针
题目描述 给定一个链表,判断链表中是否有环. 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的 ...
- LeetCode 142:环形链表 II Linked List Cycle II
给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始). 如果 pos 是 - ...
- LeetCode 141:环形链表 Linked List Cycle
给定一个链表,判断链表中是否有环. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始). 如果 pos 是 -1,则在该链表中没有环. Given a l ...
- 【LeetCode】141.环形链表
题目描述 141.环形链表 给定一个链表,判断链表中是否有环. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始). 如果 pos 是 -1,则在该链表中 ...
- 【LeetCode】142. 环形链表 II
142. 环形链表 II 知识点:链表:set:快慢指针 题目描述 给定一个链表,判断链表中是否有环. 给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 为了表示给定链表 ...
- leetcode题目142.环形链表Ⅱ(中等)
题目描述: 给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始). 如果 p ...
- LeetCode题解-147 对链表进行插入排序
对链表进行插入排序. 插入排序的动画演示如上.从第一个元素开始,该链表可以被认为已经部分排序(用黑色表示). 每次迭代时,从输入数据中移除一个元素(用红色表示),并原地将其插入到已排好序的链表中. 插 ...
- LeetCode题解-147 对链表进行插入排序 Medium
对链表进行插入排序. 插入排序的动画演示如上.从第一个元素开始,该链表可以被认为已经部分排序(用黑色表示). 每次迭代时,从输入数据中移除一个元素(用红色表示),并原地将其插入到已排好序的链表中. 插 ...
随机推荐
- OpenDiscussion_DataDrivenDesign
本文源于公司内部技术交流,如有不当之处,还请指正. Content: 1. What is Data-driven design? 2. WPF revolution. 3. More about O ...
- Spring 开发第一步(二)
今天继续学习<Spring in action 3rd>并运行书中的例子,到了第4章aop,是加入一个作为切面的Audience类,将Performer的perform()方法作为切点来进 ...
- SqlAlchemy操作(二)
SQLALchemy初始化链接数据库 1. 数据库配置. https://www.cnblogs.com/mengbin0546/p/10124560.html 2. python端操作. 一. ...
- python 函数中使用全局变量
python 函数中如果需要使用全局变量,需要使用 global + 变量名 进行声明, 如果不声明,那么就是重新定义一个局部变量,并不会改变全局变量的值 n [1]: a = 3 In [2]: d ...
- Python面向对象(类的成员之属性)
day24 类的成员之属性 class Foo(): def bar(self): print("bar") @property def per(self): ') return ...
- Access 2010 应用基础 单元三:SQL查询
导语:Access查询中拉差距的部分 简单查询 [是基于单个表的查询] 无条件从数据表中选择部分字段 Select 字段列表 from 数据表 无条件从数据表中选择全部字段 Select 字段列表 f ...
- 基于Zookeeper实现的分布式互斥锁 - InterProcessMutex
Curator是ZooKeeper的一个客户端框架,其中封装了分布式互斥锁的实现,最为常用的是InterProcessMutex,本文将对其进行代码剖析 简介 InterProcessMutex基于Z ...
- 【zookeeper】Apache curator的使用及zk分布式锁实现
上篇,本篇主要讲Apache开源的curator的使用,有了curator,利用Java对zookeeper的操作变得极度便捷. 其实在学之前我也有个疑虑,我为啥要学curator,撇开涨薪这些外在的 ...
- vue复选框选中值获取
<div id="d5"> <p>{{box5.toString()}}</p> <input type="checkbox&q ...
- 题解 P3628 【[APIO2010]特别行动队 】
题目大意 给你一个序列, 将这个序列分成若干段, 每一段的贡献为 \(ax ^ 2 + bx + c\)(x 为 这一段的权值之和) 具体思路 50pts 考虑Dp, 设\(Dp_i\)为前i ...