【Leetcode】解題筆記 2 ——42.接雨水

題目描述

給定 n 個非負整數表示每個寬度爲 1 的柱子的高度圖,計算按此排列的柱子,下雨之後能接多少雨水
在這裏插入圖片描述
上面是由數組 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度圖,在這種情況下,可以接 6 個單位的雨水(藍色部分表示雨水)

輸入: [0,1,0,2,1,0,1,3,2,1,2,1]
輸出: 6

解法一:行計算

解題思路

以行方式計算接水高度,假設行數爲j,當前高度爲height[i],用temp存儲每行一共可以存儲的水量,初始爲0,設置ans爲總儲水量,初始爲0。
如果height[i] >= j,則說明數組當前高度無法存儲水;
如果height[i] < j,則說明當前高度可以存儲1個單位的水量,因此temp+=1;
以上圖爲例,當i=1進行以下步驟:
height[0] = 0 < 1, temp = 0;
height[1] = 1 >= 1, ans += temp, temp = 0;
height[2] = 0 < 1, temp += 1;
height[3] = 2 >= 1, ans += temp, temp = 0;
height[4] = 1 >= 1, ans += temp, temp = 0;
height[5] = 0 < 1, temp += 1;
height[6] ~ height[11] 值都大於等於1,因此步驟都爲ans += temp, temp = 0;

代碼實現

解法一:行計算

class Solution:
   def trap(self, height: List[int]) -> int:
       hmax = 0
       hl = len(height)
       for i in range(hl):
           if height[i] > hmax:
               hmax = height[i]
       ans = 0
       temp = 0
       for i in range(1, hmax + 1):
           flag = 0
           temp = 0
           for j in range(hl):
               if height[j] < i and flag == 1:
                   temp += 1
               if height[j] >= i:
                   flag = 1
                   ans += temp
                   temp = 0
   
       return ans

複雜度分析

時間複雜度 O(nh)O(n*h),其中有hh行,每行進行nn次計算。
空間複雜度 O(1)O(1)

解法二:列計算

解題思路

對於當前列,只需要關注其左邊最高列left_max和右邊最高列right_max即可,選擇左、右最高列中較矮的一列,即min_num = min(left_max,right_max)。設置ans爲總儲水量,初始爲0。將min_num與當前列height[i]進行對比,有以下兩種情況:
height[i] < min_num:那麼說明當前列可以存儲水,水量爲min_num-height[i];
height[i] >= min_num:當前列無法存儲水,水量爲0;
因此對數組的每個高度爲ans += max(min_num - height[i],0)

代碼實現

class Solution:
   def trap(self, height: List[int]) -> int:
       lh = len(height)
       ans = 0
       for i in range(lh):
           left_max = 0
           for j in range(i):
               if left_max < height[j]:
                   left_max = height[j]
           right_max = 0
           for j in range(lh - 1, i, -1):
               if right_max < height[j]:
                   right_max = height[j]
                   
           min_num = min(left_max,right_max)
           ans += min(0,min_num - height[i])

       return ans

複雜度分析

時間複雜度 O(n2)O(n^2),每個列都要計算一次左邊最高列和右邊最高列,複雜度爲nn,計算nn次。
空間複雜度 O(1)O(1)

解法三:動態規劃

解題思路

根據解法二,可以知道,當前高度height[i]只要找到其左邊最高列和右邊最高列即可,因此解法三可以對解法二進行算法的優化。
left_max[i] 代表第 i 列左邊最高的牆的高度,right_maxt[i] 代表第 i 列右邊最高的牆的高度,那麼可以根據動態規劃得到公式如下:
left_max[i] = max(left_max[i-1],height[i-1]):前一列的左邊的最高列與前一列的高度選較大的,作爲當前列左邊最高列;
right_max[i] = max(right_max[i+1],height[i+1]):後一列的右邊的最高列與後一列的高度選較大的,作爲當前列右邊最高列;

代碼實現

class Solution:
  def trap(self, height: List[int]) -> int:
      lh = len(height)
      left_max = [0 for _ in range(lh)]
      right_max = [0 for _ in range(lh)]
      ans = 0
      for i in range(1,lh):
          left_max[i] = max(left_max[i-1],height[i-1])
      
      for i in range(lh-2,-1,-1):
          right_max[i] = max(right_max[i+1],height[i+1])

      for i in range(1,lh-1):
          maxnum = min(left_max[i],right_max[i])
          if maxnum > height[i]:
              ans += maxnum - height[i]
      
      return ans

複雜度分析

時間複雜度 O(n)O(n),只要計算一次左邊最高列和右邊最高列並且保存下來即可,複雜度爲11,計算nn次。
空間複雜度 O(n)O(n)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章