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\) 为链表的节点数,按照链表中是否存在环,分两种情况进行讨论:

    1. 链表中不存在环:快指针会优先到达链表尾部(最多只需要 \(n/2\) 次),时间复杂度为 \(O(n)\)
    2. 链表中存在环:我们可以把慢指针的移动分解成两个部分,“直线“部分和”环形“部分。对于”直线“部分,假设链表中”直线“部分的长度为 \(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_环形链表的更多相关文章

  1. [LeetCode题解]142. 环形链表 II | 快慢指针

    解题思路 本题是在141. 环形链表基础上的拓展,如果存在环,要找出环的入口. 如何判断是否存在环,我们知道通过快慢指针,如果相遇就表示有环.那么如何找到入口呢? 如下图所示的链表: 当 fast 与 ...

  2. [LeetCode题解]141. 环形链表 | 快慢指针

    题目描述 给定一个链表,判断链表中是否有环. 如果链表中有某个节点,可以通过连续跟踪 next 指针再次到达,则链表中存在环. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的 ...

  3. LeetCode 142:环形链表 II Linked List Cycle II

    给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始). 如果 pos 是 - ...

  4. LeetCode 141:环形链表 Linked List Cycle

    给定一个链表,判断链表中是否有环. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始). 如果 pos 是 -1,则在该链表中没有环. Given a l ...

  5. 【LeetCode】141.环形链表

    题目描述 141.环形链表 给定一个链表,判断链表中是否有环. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始). 如果 pos 是 -1,则在该链表中 ...

  6. 【LeetCode】142. 环形链表 II

    142. 环形链表 II 知识点:链表:set:快慢指针 题目描述 给定一个链表,判断链表中是否有环. 给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 为了表示给定链表 ...

  7. leetcode题目142.环形链表Ⅱ(中等)

    题目描述: 给定一个链表,返回链表开始入环的第一个节点. 如果链表无环,则返回 null. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始). 如果 p ...

  8. LeetCode题解-147 对链表进行插入排序

    对链表进行插入排序. 插入排序的动画演示如上.从第一个元素开始,该链表可以被认为已经部分排序(用黑色表示). 每次迭代时,从输入数据中移除一个元素(用红色表示),并原地将其插入到已排好序的链表中. 插 ...

  9. LeetCode题解-147 对链表进行插入排序 Medium

    对链表进行插入排序. 插入排序的动画演示如上.从第一个元素开始,该链表可以被认为已经部分排序(用黑色表示). 每次迭代时,从输入数据中移除一个元素(用红色表示),并原地将其插入到已排好序的链表中. 插 ...

随机推荐

  1. 【转】PHP操作MongoDB【NoSQL】

    原文:http://blog.sina.com.cn/s/blog_4b67d3240101519b.html 一.MongoDB简介 MongoDB (名称来自"humongous&quo ...

  2. C# 获取相对路径(绝对路径转相对路径)

    这个的方法有很多吧. 1. 用PInvok调用Windows API的PathRelativePathTo 2. 自行处理字符串 3. 利用Uri 前两种就不说了,觉得有点麻烦,想了解的同学,自已,百 ...

  3. LeetCode145:Binary Tree Postorder Traversal

    题目: Given a binary tree, return the postorder traversal of its nodes' values. For example: Given bin ...

  4. asp.net—单例模式

    一.单例模式是什么? 定义:确保一个类仅仅能产生一个实例,并且提供一个全局访问点来获取该实例. 二.单例模式怎么用? class SingleCase { public string Name{get ...

  5. js 利用数组实现类似于asp中的数据字典

    ---恢复内容开始--- 首先声明一个数组 var dictNew=new Array; var key; var value; for (var i = 0; i <50; i++) { // ...

  6. C# Task

    Task是一种基于任务的编程模型.它与thread的主要区别是,它更加方便对线程进程调度和获取线程的执行结果. Task类和thread类,前者接收的是Action委托类型,后者接收的是Func委托类 ...

  7. 【cocos2d-x 仙凡奇缘-网游研发(2) 角色换线系统】

    转载请注明出处:http://www.cnblogs.com/zisou/p/xianfan01.html 做一款游戏就先得制作好策划文档,和基本的人物世界构架的设计,然后架空在这样一个虚拟的世界中每 ...

  8. python+pcap+dpkt 抓包小实例

    #!/usr/bin/env python # -*- coding: utf-8 -*- """ 网络数据包捕获与分析程序 """ imp ...

  9. 程序媛计划——SQLite初级

    数据库简介 数据库定义: 指的是以一定方式储存在一起.能为多个用户共享.具有尽可能小的冗余度.与应用程序彼此独立的数据集合.是带有相关数据的表的集合. 数据库是由行和列组成的二维表. 字段: 数据库表 ...

  10. php错误控制运算符@

    PHP支持一个错误控制运算符:@.当将其放置在一个PHP表达式之前,该表达式可能产生的任何错误信息都被忽略掉. 如果用set_error_handle()设定了自定义的错误处理函数,仍然会被调用,但是 ...