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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM