525. Contiguous Array
你寫得已經很清楚了,邏輯也都有講到,下面是我幫你稍微整理潤飾、補充說明的版本,也加了一些小細節讓整體更容易閱讀和理解,給你參考:
525. Contiguous Array
題目給定一個只包含 0
和 1
的陣列,請找出其中最長的子陣列,這個子陣列必須滿足包含相同數量的 0
和 1
。
暴力解法(不推薦)
可以用暴力法遍歷所有子陣列,然後統計 0
和 1
的個數來檢查是否相等。不過這種方法的時間複雜度為 $O(n^2)$,在陣列長度較大時效率太差。
優化思路
這題其實是一個經典的 prefix sum + hashmap 題型,但不容易直接看出來,屬於那種「看過就秒懂、沒看過很難自己想到」的題目。
這題的第一個關鍵在於:
👉 將問題轉換為 prefix sum 的形式來解。
因為我們想要找的是 0
和 1
數量相同的子陣列,我們可以把陣列中的 0
全部視為 -1
,這樣就把問題轉換為:
➡️「找到一段子陣列,總和為 0
」。
第二個關鍵點:怎麼有效率地找到總和為 0 的子陣列?
我們可以邊走邊累加 prefix sum(前綴總和),同時使用一個 哈希表
(dict
)來記錄每個前綴和第一次出現的位置。
為什麼這樣做?
因為如果在 index i
和 j
(i < j
)都出現了相同的 prefix sum,代表從 i+1
到 j
之間的元素總和為 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」的最長距離。