• 141. 环形链表


    问题描述

    给定一个链表,判断链表中是否有环。

    为了表示给定链表中的环,我们使用整数 pos来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos-1,则在该链表中没有环。

    示例 1:

    输入:head = [3,2,0,-4], pos = 1
    输出:true
    解释:链表中有一个环,其尾部连接到第二个节点。
    

    进阶:

    你能用 O(1)(即,常量)内存解决此问题吗?

    解决方案

    快慢指针法

    想象一下,有两个速度不同的跑步者。如果他们在直路上行驶,快跑者将首先到达目的地。但是,如果它们在圆形跑道上跑步,那么快跑者如果继续跑步就会追上慢跑者。

    这正是我们在链表中使用两个速度不同的指针时会遇到的情况:

    1. 如果没有环,快指针将停在链表的末尾。
    2. 如果有环,快指针最终将与慢指针相遇。

    所以剩下的问题是:

    这两个指针的适当速度应该是多少?

    一个安全的选择是每次移动慢指针一步,而移动快指针两步。每一次迭代,快速指针将额外移动一步。如果环的长度为 M,经过 M 次迭代后,快指针肯定会多绕环一周,并赶上慢指针。

    时间复杂度:O(n)

    空间复杂度:O(1)

    show me the code

    class Solution(object):
        def hasCycle(self, head):
            """
            :type head: ListNode
            :rtype: bool
            """
    
            quick_pointer = slow_pointer = head             # 创建两个指针,分别记录一个快的遍历指针,和一个慢的便利指针
    
            while quick_pointer and quick_pointer.next:     # 当快指针为None,或快指针的下个一对象为None,说明不是环形链表
                slow_pointer = slow_pointer.next            # 慢指针前进一步
                quick_pointer = quick_pointer.next.next     # 快指针前进两步
                if slow_pointer == quick_pointer:           # 假如快指针等于慢指针,说明为环形链表
                    return True
            return False
    

    hash表存贮法

    顺序遍历链表所有节点,若出现重复访问则说明有环,否则说明无环。这里注意不能用list保存访问过的节点,查找太慢了;用dict保存还要考虑到键不能是对象,所以这里采取以对象的id作为键的做法。

    时间复杂度:O(n)

    空间复杂度:O(n)

    show me the code

    class Solution2(object):
        def hasCycle(self, head):
            """
            :type head: ListNode
            :rtype: bool
            """
            my_dict = {}                        # 创建一个字典来保存已经遍历过节点的内存地址
            while head and head.next:           # 当快指针为None,或快指针的下个一对象为None,说明不是环形链表
                if id(head) in my_dict:         # 假如当前节点在字典中则说明是环形链表
                    return True
                else:
                    my_dict[id(head)] = True    # 将当前节点加入到字典中
    
            return False
    

    逆转链表检测法

    倘若一个链表存在环,那么将这个链表反转,反转后的链表和原链表具有相同的head。证明起来比较麻烦,可以在纸上画一画来验证。

    时间复杂度:O(n)

    空间复杂度:O(n)

    show me the code

    class Solution3(object):
        def reverse_list(self, head):
            before = after = None
            while head:
                after = head.next # 保存当前节点的下一个节点
                head.next = before # 将当前节点的下一题个节点替换为当前节点的上一个节点
                before = head # 将上一个节点,往前移动,变为当前节点
                head = after # 当前节点向前移动
            return before # 返回反转完成后的头结点
    
        def hasCycle(self, head):
            """
            :type head: ListNode
            :rtype: bool
            """
            if head and head.next and head == self.reverse_list(head): # 加入反转后的头结点与原先的头结点相同,则说明有环
                return True
            return False
    
  • 相关阅读:
    内建函数
    urllib学习
    Jupyter Notebook介绍、安装及使用教程
    grep详解、sed详解、awk详解
    正则表达式
    RedisClient.SetRandomMember
    redis 队列
    hmGet
    redis trim
    大O符号
  • 原文地址:https://www.cnblogs.com/huang-yc/p/10667642.html
Copyright © 2020-2023  润新知