Leetcode142:环形链表

目录

一、题目

二、示例

三、思路

四、代码


一、题目

给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。

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

说明:不允许修改给定的链表。

进阶:

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

二、示例

示例1:

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

示例2:

输入:head = [1,2], pos = 0
输出:tail connects to node index 0
解释:链表中有一个环,其尾部连接到第一个节点。

示例3:

输入:head = [1], pos = -1
输出:no cycle
解释:链表中没有环。

提示:

  • 链表中节点的数目范围是 [0, 104]
  • -105 <= Node.val <= 105
  • pos 为 -1 或者链表中的一个 有效索引

三、思路

1、哈希表:遍历所有的节点,每次遍历一个节点时,判断该节点之前是否被遍历过。

复杂度:

时间复杂度:O(N)

空间复杂度:O(N)

2、(进阶)快慢指针:

首先,定义两个指针,快指针fast,慢指针slow,fast指针每次移动两个节点,slow指针每次移动一个节点。如果量两指针在移动过程中相遇,则链表有环,否则,无环。

那么其中的原理是什么呢?

第一种情况,链表无环,那么fast指针一定先比slow指针移动到链表尾部,并且fast指针始终在slow指针前面(除始发位置),因此两指针一定不会相遇;

第二种情况,链表有环。正如龟兔赛跑一样,假想「乌龟」和「兔子」在链表上移动,「兔子」跑得快,「乌龟」跑得慢。那么「兔子」会先于「乌龟」进入环,并且一直在环内移动。等到「乌龟」进入环时,由于「兔子」的速度快,它一定会在某个时刻与乌龟相遇,即套了「乌龟」若干圈。

如下图所示,设链表中环外部分的长度为 a。slow 指针进入环后,又走了 b 的距离与 fast 相遇。

此时,fast 指针已经走完了环的 n 圈,因此fast走过的总距离为 a+n(b+c)+b;slow指针走过的距离总距离为 a + b。

又因为fast指针所走的距离是slow指针的2倍,因此得到以下公式:

a+n(b+c)+b = 2(a + b)

得:a=c+(n−1)(b+c) 其中n为走过的圈数,未知数

我们会发现:从相遇点到入环点的距离加上 n-1n−1 圈的环长,恰好等于从链表头部到入环点的距离。

因此,当发现 slow 与 fast 相遇时,我们再额外使用一个指针 q。起始,它指向链表头部;随后,q和slow 每次向后移动一个位置。最终,它们会在入环点相遇。

fig1

复杂度:

时间复杂度:O(N)

空间复杂度:O(1)

四、代码 

1、

# Definition for singly-linked list.
class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None

class Solution:
    def detectCycle(self, head: ListNode) -> ListNode:
        s = set()
        while(head):
            if head in s:
                return head
            else:
                s.add(head)
            head = head.next

if __name__ == '__main__':
    head = ListNode(3)
    head.next = ListNode(2)
    head.next.next = ListNode(0)
    head.next.next.next = ListNode(4)
    head.next.next.next.next = head.next

    s = Solution()
    ans = s.detectCycle(head)
    print(ans) 

2、

# Definition for singly-linked list.
class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None

class Solution:
    def detectCycle(self, head: ListNode):
        fast, slow = head, head
        while fast and fast.next:
            fast = fast.next.next
            slow = slow.next
            if fast == slow:
                q = head
                while q != slow:
                    q = q.next
                    slow = slow.next
                return q
        return None

if __name__ == '__main__':
    head = ListNode(3)
    head.next = ListNode(2)
    head.next.next = ListNode(0)
    head.next.next.next = ListNode(4)
    head.next.next.next.next = head.next

    s = Solution()
    ans = s.detectCycle(head)
    print(ans)

猜你喜欢

转载自blog.csdn.net/weixin_45666660/article/details/108992810