Description

給定整數陣列 nums,回傳所有元素全為 0 的子陣列數量。

Example:

Input: nums = [1,3,0,0,2,0,0,4] Output: 6 ([0], [0], [0,0], [0], [0], [0,0] 共 6 個全零子陣列)

Intuition#

核心思路:連續 k 個 0 會產生 k*(k+1)/2 個全零子陣列。遍歷陣列計算每段連續 0 的長度即可。

  • 等價於:對每段連續 0 的長度 k,貢獻 1 + 2 + ... + k = k*(k+1)/2
  • 也可以邊遍歷邊累加:每遇到一個 0,它能與前面的連續 0 組成的子陣列數等於目前連續 0 的長度

Approaches#

1: Count Consecutive Zeros (Segment)#

  • 概念: 找出每段連續 0 的長度 k,用公式 k*(k+1)/2 累加
  • 時間複雜度: O(n) - 一次遍歷
  • 空間複雜度: O(1) - 常數空間
class Solution {
    fun zeroFilledSubarray(nums: IntArray): Long {
        var result = 0L
        var consecutive = 0L

        for (num in nums) {
            if (num == 0) {
                consecutive++
            } else {
                result += consecutive * (consecutive + 1) / 2
                consecutive = 0
            }
        }
        result += consecutive * (consecutive + 1) / 2

        return result
    }
}

⭐2: Running Count (One-Pass)#

  • 概念: 維護當前連續 0 的長度 count,每遇到一個 0 就 count++ 並將 count 累加到結果(第 k 個 0 新增 k 個子陣列)
  • 時間複雜度: O(n) - 一次遍歷
  • 空間複雜度: O(1) - 常數空間
class Solution {
    fun zeroFilledSubarray(nums: IntArray): Long {
        var result = 0L
        var count = 0L

        for (num in nums) {
            if (num == 0) {
                count++
                result += count
            } else {
                count = 0
            }
        }

        return result
    }
}

為什麼每個新 0 貢獻 count 個子陣列?因為以當前位置為結尾的全零子陣列有 count 個(長度分別為 1, 2, …, count,但這裡只新增長度為 1 到 count 中以當前 0 結尾的那個)。實際上每個 0 作為新的結尾,恰好新增 count 個以它結尾的全零子陣列。

🔑 Takeaways#

  • Pattern: 連續子陣列計數 -> Running Count 累加
  • 關鍵技巧: 「以當前元素結尾」的思維方式:第 k 個連續 0 作為結尾新增 k 個子陣列。這個模式適用於很多「計數特定子陣列」的問題