525. Contiguous Array

525. Contiguous Array

你寫得已經很清楚了,邏輯也都有講到,下面是我幫你稍微整理潤飾、補充說明的版本,也加了一些小細節讓整體更容易閱讀和理解,給你參考:


525. Contiguous Array

題目給定一個只包含 01 的陣列,請找出其中最長的子陣列,這個子陣列必須滿足包含相同數量的 01


暴力解法(不推薦)

可以用暴力法遍歷所有子陣列,然後統計 01 的個數來檢查是否相等。不過這種方法的時間複雜度為 $O(n^2)$,在陣列長度較大時效率太差。


優化思路

這題其實是一個經典的 prefix sum + hashmap 題型,但不容易直接看出來,屬於那種「看過就秒懂、沒看過很難自己想到」的題目。

這題的第一個關鍵在於:
👉 將問題轉換為 prefix sum 的形式來解。

因為我們想要找的是 01 數量相同的子陣列,我們可以把陣列中的 0 全部視為 -1,這樣就把問題轉換為:
➡️「找到一段子陣列,總和為 0」。


第二個關鍵點:怎麼有效率地找到總和為 0 的子陣列?

我們可以邊走邊累加 prefix sum(前綴總和),同時使用一個 哈希表dict)來記錄每個前綴和第一次出現的位置

為什麼這樣做?
因為如果在 index iji < j)都出現了相同的 prefix sum,代表從 i+1j 之間的元素總和為 0,這樣就可以構成一個符合條件的子陣列。


程式碼:

class Solution:
    def findMaxLength(self, nums: List[int]) -> int:
        n = len(nums)
        # 建立前綴總和陣列
        preSum = [0] * (n + 1)
        for i in range(n):
            # 把 0 當作 -1,這樣總和為 0 表示 0 和 1 一樣多
            preSum[i + 1] = preSum[i] + (-1 if nums[i] == 0 else 1)
        
        # 用 dict 紀錄 prefix sum 最早出現的位置
        vToi = {}
        res = 0
        for i in range(n + 1):
            if preSum[i] not in vToi:
                vToi[preSum[i]] = i  # 第一次出現時記下 index
            else:
                # 找到之前有一樣的總和,計算長度
                res = max(res, i - vToi[preSum[i]])
        return res

時間與空間複雜度分析:

  • 時間複雜度:O(n),只遍歷了一次陣列。
  • 空間複雜度:O(n),用了一個 dict 存每個 prefix sum 出現的位置。

小總結

這題的精髓:

  • 想到把 0 當作 -1,然後轉換成總和為 0 的問題。
  • 用 prefix sum + hashmap 找到「子陣列總和為 0」的最長距離。