[LeetCode解題攻略] 42. Trapping Rain Water

更新於 發佈於 閱讀時間約 7 分鐘

題目描述

給定一個整數數組 height,每個元素表示一個柱子的高度,其中每個柱子的寬度為 1,請計算柱子之間可以容納多少雨水。


範例

範例 1

輸入: height = [0,1,0,2,1,0,1,3,2,1,2,1]
輸出: 6
raw-image


範例 2

輸入: height = [4,2,0,3,2,5]
輸出: 9

解題思路

這是一個經典的動態規劃與雙指針問題。

  1. 直觀思路
    雨水能夠存儲的量由兩側的最高柱子決定,對於每個柱子,我們需要知道:
    • 它左側最高柱子的高度。
    • 它右側最高柱子的高度。
    • 存水量 = min(左側最高高度, 右側最高高度) - 當前高度。
  2. 優化
    • 可以使用兩種方法:動態規劃 或 雙指針法。

解法一:暴力解法

核心思想

對於每個柱子,找到其左側和右側的最大高度,計算可以容納的雨水量。


程式碼

class Solution(object):
def trap(self, height):
"""
:type height: List[int]
:rtype: int
"""
n = len(height)
if n == 0:
return 0

water_trapped = 0
for i in range(n):
# 找到左側最大高度
left_max = max(height[:i+1])
# 找到右側最大高度
right_max = max(height[i:])
# 計算雨水量
water_trapped += min(left_max, right_max) - height[i]

return water_trapped

時間與空間複雜度

  • 時間複雜度:O(n^2)
    • 對於每個柱子,我們需要遍歷一次找左、右最大高度。
  • 空間複雜度:O(1)
    • 不需要額外的儲存空間。

解法二:動態規劃

核心思想

用兩個數組 left_maxright_max 分別保存每個柱子的左側和右側最大高度,避免暴力解法中重複計算。


步驟

  1. 建立兩個數組:
    • left_max[i] 表示 i 左側的最大高度(包含自己)。
    • right_max[i] 表示 i 右側的最大高度(包含自己)。
  2. 遍歷柱子,計算每個位置的存水量。

程式碼

class Solution(object):
def trap(self, height):
n = len(height)
if n == 0:
return 0

# 預處理左側和右側最大高度
left_max = [0] * n
right_max = [0] * n

left_max[0] = height[0]
for i in range(1, n):
left_max[i] = max(left_max[i-1], height[i])

right_max[n-1] = height[n-1]
for i in range(n-2, -1, -1):
right_max[i] = max(right_max[i+1], height[i])

# 計算存水量
water_trapped = 0
for i in range(n):
water_trapped += min(left_max[i], right_max[i]) - height[i]

return water_trapped

時間與空間複雜度

  • 時間複雜度:O(n)
    • 需要兩次遍歷計算 left_max 和 right_max,以及一次遍歷計算雨水量。
  • 空間複雜度:O(n)
    • 額外使用了 left_max 和 right_max 數組。

解法三:雙指針法

核心思想

使用兩個指針 leftright 來替代 left_maxright_max 數組,只需維護當前的左右最大高度即可。


步驟

  1. 使用雙指針 leftright,分別指向數組的開頭和結尾。
  2. 維護左右最大高度 left_maxright_max
  3. 如果左側最大高度小於右側最大高度:
    • 判斷當前柱子是否可以存水:left_max - height[left]。
    • 然後移動 left 指針。
  4. 如果右側最大高度小於左側最大高度:
    • 判斷當前柱子是否可以存水:right_max - height[right]。
    • 然後移動 right 指針。

程式碼

class Solution(object):
def trap(self, height):
n = len(height)
if n == 0:
return 0

left, right = 0, n - 1
left_max, right_max = 0, 0
water_trapped = 0

while left < right:
if height[left] < height[right]:
if height[left] >= left_max:
left_max = height[left]
else:
water_trapped += left_max - height[left]
left += 1
else:
if height[right] >= right_max:
right_max = height[right]
else:
water_trapped += right_max - height[right]
right -= 1

return water_trapped

時間與空間複雜度

  • 時間複雜度:O(n)
    • 雙指針從頭到尾只遍歷一次數組。
  • 空間複雜度:O(1)
    • 只使用了常數級別的額外變量。

結論

  1. 雙指針法 是最優解,時間與空間複雜度均表現優秀。
  2. 動態規劃法 提供了清晰的分步邏輯,適合學習初期使用。
  3. 暴力解法 雖然直觀,但不推薦在大型數組中使用。

你可以根據自己的熟悉程度選擇適合的解法!

留言
avatar-img
留言分享你的想法!
avatar-img
追極光的北極熊|軟體工程師的小天地
12會員
163內容數
歡迎來到我的部落格!這裡記錄了軟體工程師的日常生活點滴,並分享程式設計與演算法的實用教學。無論你是初學者還是有經驗的開發者,都能在這裡找到深入淺出的技術解析與實戰技巧。此外,我也會分享工作中的心路歷程與學習心得,讓你不僅學到技術,更能瞭解軟體開發的實際應用與挑戰。希望透過這個平台,能與你共同成長,激發對技術的熱情!
2025/04/04
給定一個非負整數陣列 nums,其中 nums[i] 代表你在索引 i 處最多可以向右跳幾步。 請判斷是否能夠從索引 0 跳到最後一個索引。
2025/04/04
給定一個非負整數陣列 nums,其中 nums[i] 代表你在索引 i 處最多可以向右跳幾步。 請判斷是否能夠從索引 0 跳到最後一個索引。
2025/03/28
給定一個 m x n 的矩陣 matrix,請按照 螺旋順序(spiral order) 返回矩陣中的所有元素。
2025/03/28
給定一個 m x n 的矩陣 matrix,請按照 螺旋順序(spiral order) 返回矩陣中的所有元素。
2025/03/20
這道題是 LeetCode 的經典題之一,要求我們找出 一個子陣列,使其和最大,並返回這個最大和的數值。
2025/03/20
這道題是 LeetCode 的經典題之一,要求我們找出 一個子陣列,使其和最大,並返回這個最大和的數值。
看更多
你可能也想看
Thumbnail
常常被朋友問「哪裡買的?」嗎?透過蝦皮分潤計畫,把日常購物的分享多加一個步驟,就能轉換成現金回饋。門檻低、申請簡單,特別適合學生與上班族,讓零碎時間也能創造小確幸。
Thumbnail
常常被朋友問「哪裡買的?」嗎?透過蝦皮分潤計畫,把日常購物的分享多加一個步驟,就能轉換成現金回饋。門檻低、申請簡單,特別適合學生與上班族,讓零碎時間也能創造小確幸。
Thumbnail
嗨!歡迎來到 vocus vocus 方格子是台灣最大的內容創作與知識變現平台,並且計畫持續拓展東南亞等等國際市場。我們致力於打造讓創作者能夠自由發表、累積影響力並獲得實質收益的創作生態圈!「創作至上」是我們的核心價值,我們致力於透過平台功能與服務,賦予創作者更多的可能。 vocus 平台匯聚了
Thumbnail
嗨!歡迎來到 vocus vocus 方格子是台灣最大的內容創作與知識變現平台,並且計畫持續拓展東南亞等等國際市場。我們致力於打造讓創作者能夠自由發表、累積影響力並獲得實質收益的創作生態圈!「創作至上」是我們的核心價值,我們致力於透過平台功能與服務,賦予創作者更多的可能。 vocus 平台匯聚了
Thumbnail
給定一個整數數組 height,每個元素表示一個柱子的高度,其中每個柱子的寬度為 1,請計算柱子之間可以容納多少雨水。
Thumbnail
給定一個整數數組 height,每個元素表示一個柱子的高度,其中每個柱子的寬度為 1,請計算柱子之間可以容納多少雨水。
Thumbnail
題目敘述 Patching Array 題目給定一個整數陣列, 請問還要補上多少個數字,才能用這些數字的和拼湊出所有1~n的整數。
Thumbnail
題目敘述 Patching Array 題目給定一個整數陣列, 請問還要補上多少個數字,才能用這些數字的和拼湊出所有1~n的整數。
Thumbnail
Leetcode 精選75題 題目與題解 熱門考點 目錄 (持續更新中) 建議從左側目錄 或者 按Ctrl+F輸入關鍵字進行搜尋
Thumbnail
Leetcode 精選75題 題目與題解 熱門考點 目錄 (持續更新中) 建議從左側目錄 或者 按Ctrl+F輸入關鍵字進行搜尋
Thumbnail
題目給定一個布林代數的二元樹,要求我們計算最後的結果。 葉子節點都是真假值 非葉子節點都是布林運算子
Thumbnail
題目給定一個布林代數的二元樹,要求我們計算最後的結果。 葉子節點都是真假值 非葉子節點都是布林運算子
Thumbnail
輸入給定一個已經從小到大排序好,而且彼此互質的整數陣列, 請問任取兩數分別當作分子、分母,第k小的分數是多少? 輸出請以 [分子,分母] 的形式回傳答案。
Thumbnail
輸入給定一個已經從小到大排序好,而且彼此互質的整數陣列, 請問任取兩數分別當作分子、分母,第k小的分數是多少? 輸出請以 [分子,分母] 的形式回傳答案。
Thumbnail
題目敘述 題目會給定一棵二元樹的根結點, 要求我們計算滿足局部路徑節點和=targetSum的數目有多少? 註: 局部路徑節點和 =由節點a往下走到某個節點b,這個區間內的節點值總和 題目的原文敘述 測試範例 Example 1: Input: root = [10,5,-3,3
Thumbnail
題目敘述 題目會給定一棵二元樹的根結點, 要求我們計算滿足局部路徑節點和=targetSum的數目有多少? 註: 局部路徑節點和 =由節點a往下走到某個節點b,這個區間內的節點值總和 題目的原文敘述 測試範例 Example 1: Input: root = [10,5,-3,3
Thumbnail
題目會給定一個輸入陣列temperatures ,分別代表每一天的溫度。 請計算每一天還要再過幾天才會遇到更溫暖的日子,如果遇不到,則回填0。 請以陣列的形式返回答案。 題目的原文敘述 約束條件 Constraints: 1 <= temperatures.length <= 10^
Thumbnail
題目會給定一個輸入陣列temperatures ,分別代表每一天的溫度。 請計算每一天還要再過幾天才會遇到更溫暖的日子,如果遇不到,則回填0。 請以陣列的形式返回答案。 題目的原文敘述 約束條件 Constraints: 1 <= temperatures.length <= 10^
Thumbnail
題目敘述 題目會給我們一個輸入陣列nums,每個元素值代表那個格子點可以跳躍的最大長度。 一開始從最左邊的格子點出發開始跳,請問可以成功抵達終點,也就是最右邊的格子點嗎? 如果可以,返回 True。 如果不行,返回False。 題目的原文敘述 測試範例 Example 1: In
Thumbnail
題目敘述 題目會給我們一個輸入陣列nums,每個元素值代表那個格子點可以跳躍的最大長度。 一開始從最左邊的格子點出發開始跳,請問可以成功抵達終點,也就是最右邊的格子點嗎? 如果可以,返回 True。 如果不行,返回False。 題目的原文敘述 測試範例 Example 1: In
Thumbnail
題目敘述 題目會給我們一個隔板陣列height,代表每個隔板的高度,讓我們選取兩個隔板作為水槽的邊界,請問最多我們能裝多少水? 題目的原文敘述 測試範例 Example 1: Input: height = [1,8,6,2,5,4,8,3,7] Output: 49 Explanati
Thumbnail
題目敘述 題目會給我們一個隔板陣列height,代表每個隔板的高度,讓我們選取兩個隔板作為水槽的邊界,請問最多我們能裝多少水? 題目的原文敘述 測試範例 Example 1: Input: height = [1,8,6,2,5,4,8,3,7] Output: 49 Explanati
Thumbnail
題目會給我們一個陣列,分別代表高低各不同的隔板高度,問我們從降雨之後,最多可以儲存多少水量?
Thumbnail
題目會給我們一個陣列,分別代表高低各不同的隔板高度,問我們從降雨之後,最多可以儲存多少水量?
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News