日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

每天一道LeetCode-----计算一个直方图空隙的容量(如果装水能装多少)

發(fā)布時間:2024/4/19 编程问答 55 豆豆
生活随笔 收集整理的這篇文章主要介紹了 每天一道LeetCode-----计算一个直方图空隙的容量(如果装水能装多少) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Trapping Rain Water

原題鏈接Trapping Rain Water

給定一序列,表示一個直方圖每個柱的高度(圖中黑色部分),計算這個直方圖可以存儲的容量(圖中淺藍色部分)

直觀的想法可能是直接求容量,比如說計算高度為2和高度為3的兩個柱子之間的容量,但是需要減去二者之間的其他柱子所占的面積,比較麻煩。

從圖中可以看出,對于某個柱子,判斷它是否被某兩個柱子構(gòu)成的區(qū)域包含的方法,是判斷這個柱子左右兩邊是否都存在比它高的柱子。比如說從左邊開始的那個高度為2的柱子,它右邊有一個高度為3的柱子,但是左邊沒有比它再高的柱子了,所以,它不在任兩個柱子構(gòu)成的區(qū)域中。

那么可以這樣理解,判斷一個柱子是否在某兩個柱子構(gòu)成的區(qū)域中的方法,是判斷它的正上方是否有淺藍色區(qū)域。
相反,判斷一個柱子正上方是否有淺藍色方塊,只需要判斷這個柱子的左邊和右邊是否有高度大于它的柱子。而計算正上方淺藍色方塊個數(shù)的方法,是計算這個柱子左邊高度最大的柱子和右邊高度最大的柱子中高度較小的那個柱子的高度和這個柱子的高度差。

而如果垂直x軸的方向看每個柱子正上方的淺藍色方塊,可以發(fā)現(xiàn)整個容量恰好是由每個柱子正上方的淺藍色方塊組成(包括高度為0的柱子)。

綜上,只需要求每個柱子正上方淺藍色區(qū)域塊的個數(shù)(因為面積是1),而淺藍色區(qū)域塊的個數(shù)是通過左邊最高高度和右邊最大高度中較小的那個高度和當前柱子的高度作差得到。


直接求解

class Solution { public:int trap(vector<int>& height) {int ans = 0;int n = height.size();for(int i = 1; i < n - 1; ++i){int max_left = 0;int max_right = 0;/* 找當前柱子左邊的最大高度,算上當前柱子的高度 *//* 即如果左邊沒有大于當前柱子的高度,那么最大高度就是當前柱子的高度 */for(int j = i; j >= 0; --j)max_left = std::max(max_left, height[j]);/* 找右邊的最大高度,同理 */for(int j = i; j < n; ++j)max_right = std::max(max_right, height[j]);/* 兩個高度中較小的高度和當前柱子的高度差 *//* 如果max_left == height[i],那么差為0,上方?jīng)]有淺藍色塊 */ans += std::min(max_left, max_right) - height[i];}return ans;} };

動態(tài)規(guī)劃
上面的方式重復計算了很多max_left和max_right,可以用動態(tài)規(guī)劃的思想減少重復計算

class Solution { public:int trap(vector<int>& height) {if(height.empty())return 0;int n = height.size();/* 對于某個位置i,計算i左邊的最大高度 */vector<int> left_dp(n, 0);left_dp[0] = height[0];for(int i = 1; i < n; ++i)left_dp[i] = std::max(left_dp[i - 1], height[i]);/* 對于某個位置i,計算i右邊的最大高度 */vector<int> right_dp(n, 0);right_dp[n - 1] = height[n - 1];for(int i = n - 2; i >= 0; --i)right_dp[i] = std::max(right_dp[i + 1], height[i]);int ans = 0;for(int i = 1; i < n - 1; ++i)ans += std::min(left_dp[i], right_dp[i]) - height[i];return ans;} };

使用兩個指針
動態(tài)規(guī)劃的時間復雜度為O(n),空間復雜度也是O(n)。如果要將空間復雜度降到O(1),就需要實時更新max_left和max_right。
可以通過從兩邊同時向中間逼近的方法,但需要保證

  • 從左邊開始遍歷到某個柱子時,右邊一定有某個柱子的高度大于max_left。此時二者的較小值為max_left
  • 從右邊開始遍歷到某個柱子時,左邊一定有某個柱子的高度大于max_right。此時二者的較小值為max_right

要保證右邊一定有某個柱子高度大于max_left,只需要保證將max_left更改為height[left]時,height[left] < height[right]
要保證左邊一定有某個柱子高度大于max_right,只需要保證將max_right更改為height[right]時,height[right] < height[left]

所以,可以嘗試著根據(jù)height[left]和height[right]大小關(guān)系來判斷當前是應(yīng)該從左向右逼近還是從右向左逼近,即

class Solution { public:int trap(vector<int>& height) {int n = height.size();int ans = 0;int left = 0;int right = n - 1;int max_left = 0;int max_right = 0;while(left <= right){if(height[left] < height[right]){/* 在left右邊一定有某個柱子的高度大于max_left,所以較小的就是max_left* 如果當前柱子的高度大于max_left,說明左邊沒有比它高的柱子,淺藍色區(qū)域塊個數(shù)為0,此時更新max_left */(max_left < height[left]) ? (max_left = height[left]) : ans += (max_left - height[left]);++left;}else{/* 同理 */(max_right < height[right]) ? (max_right = height[right]) : ans += (max_right - height[right]);--right;}}return ans;} };

這題主要是弄清楚如何使用簡便的方法求出容量,即通過正上方的淺藍色區(qū)域塊的個數(shù)求解。同時,也需要明白如何求解淺藍色區(qū)域塊的個數(shù),即找到左右兩邊最大的高度中較小的那個和當前柱子高度作差。

總結(jié)

以上是生活随笔為你收集整理的每天一道LeetCode-----计算一个直方图空隙的容量(如果装水能装多少)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。