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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

每天一道LeetCode-----计算直方图中最大矩形的面积

發布時間:2024/4/19 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 每天一道LeetCode-----计算直方图中最大矩形的面积 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Largest Rectangle in Histogram

原題鏈接Largest Rectangle in Histogram

給定一個直方圖,計算這個直方圖中最大的矩形面積。輸入的是直方圖中每個柱的高度

首先可以想到要求面積就需要確定矩形的高度,但是每個柱子的高度是不一樣的,而不同的柱子組成的矩形要以最短的那個作為高

那么,是否可以對每個高度的分別計算面積呢?簡單的說就是以每個柱子的高度作為最后矩形的高度,計算形成的最大矩形的面積

隱含的方法就是對于每個柱子,它的高度記為H,需要

  • 向左找第一個高度小于H的柱子位置,下標記為l
  • 向右找第一個高度小于H的柱子位置,下標記為r

那么,以H作為高的矩形的寬為(r - l - 1),面積為(r - l - 1) * H

只需要把所有這樣的面積求出來取最大值即可

代碼如下

class Solution { public:int largestRectangleArea(vector<int>& heights) {int maxArea = 0;for(int i = 0; i < heights.size(); ++i){/* 向左找第一個小于當前高度的位置 */int l = i - 1;while(l >= 0 && heights[l] >= heights[i])--l;/* 向右找第一個小于當前高度的位置 */int r = i + 1;while(r < heights.size() && heights[r] >= heights[i])++r;/* 計算面積 */maxArea = std::max(maxArea, (r - l - 1) * heights[i]);}return maxArea;} };

但是,這種方法超時了:(
可以想到時間主要都消耗在內部的兩個while循環,其實循環目的沒錯,為了尋找矩形的左右邊界,但是試想,如果heights中所有元素都相等(極端情況),那么每次while循環可能都需要遍歷整個heights直到l < 0或者r >= heights.size()

可以從這兩方面入手,考慮如何優化兩個while循環


先考慮尋找左邊界時的優化

假設需要找heights[i]的左邊界,根據上述方法,需要一次遍歷

i-1, i-2, ..., k1

找到第一個k1滿足

heights[k1] < heights[i]

在下次循環中(i = i + 1),又需要找heights[i+1]的左邊界,同樣的遍歷方法

i, i-1, i-2, ..., k2

找到第一個k2滿足

heights[k2] < heights[i+1]

仔細觀察這兩次循環,實際上是存在重復部分的,在找heights[i+1]的左邊界過程中,假設有

heights[i] >= heights[i+1]

那么下次其實不需要從i-1開始繼續比較heights[i-1] >= heights[i+1],因為當遍歷i+1時,有些東西是已知的,那就是

  • 第一個小于heights[i]的位置,即k1

由于heights[i] >= heights[i+1],從i, i-1, …, k+1這些位置上的元素一定也都大于等于heights[i+1],那么為什么不從k1開始比較呢,是吧:)

當然這種方法是建立在對heights的遍歷是從左向右的,即

for(int i = 0; i < heights.size(); ++i)...//尋找heights[i]的左邊界

對于右邊界,就需要讓heights的遍歷從右向左

for(int i = heights.size() - 1; i >= 0; --i)...//尋找heights[i]的右邊界

最后再來一次循環,但是這次heights[i]的左邊界和右邊界都是已知的

class Solution { public:int largestRectangleArea(vector<int>& heights) {if(heights.empty())return 0;int n = heights.size();vector<int> L(n, 0);vector<int> R(n, 0);for(int i = 0; i < n; ++i){int l = i - 1;while(l >= 0 && heights[l] >= heights[i])l = L[l]; //直接從k1開始找L[i] = l;}for(int i = n - 1; i >= 0; --i){int r = i + 1;while(r < n && heights[r] >= heights[i])r = R[r]; //直接從k1開始找R[i] = r;}int maxArea = 0;for(int i = 0; i < n; ++i){//L[i]表示左邊第一個小于heights[i]的位置//R[i]表示右邊第一個小于heights[i]的位置maxArea = std::max(maxArea, (R[i] - L[i] - 1) * heights[i]);}return maxArea;} };

當然啦,如果覺得for循環有點多,可以把后兩個合在一起:)

class Solution { public:int largestRectangleArea(vector<int>& heights) {if(heights.empty())return 0;int n = heights.size();vector<int> L(n, 0);vector<int> R(n, 0);for(int i = 0; i < n; ++i){int l = i - 1;while(l >= 0 && heights[l] >= heights[i])l = L[l]; //直接從k1開始找L[i] = l;}int maxArea = 0;for(int i = n - 1; i >= 0; --i){int r = i + 1;while(r < n && heights[r] >= heights[i])r = R[r]; //直接從k1開始找R[i] = r;maxArea = std::max(maxArea, (R[i] - L[i] - 1) * heights[i]);}return maxArea;} };

其實通常首先想到的就是最開始那個一個for循環,內部兩個while找左右邊界的版本,但是實際上while循環是可以優化的,如果知道優化的方法(找到重復計算的原因),效率會高很多

總結

以上是生活随笔為你收集整理的每天一道LeetCode-----计算直方图中最大矩形的面积的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。