題目描述:
自己想了想發現只有暴力做,但這題明顯是有簡便算法的,網上看了看主流的解法是用單調(遞增)棧做,算法大概思想是:維護一個單調遞增序列,當前元素大於棧頂元素時則進棧,當前元素小於棧定元素時則處理完前面元素能得到的最大值後在進棧。
這種方法非常的巧妙,感覺應該是本題的最優解法了,比如你想用暴力做,max[i]代表從i號節點開始的最大矩形,對單個節點處理一次用時o(n),對每個節點都跑一次就要用時o(n方)了,然而用單調棧做的時間複雜度只要o(n)就可以完成(每個元素進棧出棧一次),因爲用單調棧做避免了大量的重複計算。
還有一點需要理解的是這段代碼:
res = max(res, height[cur] * (st.empty() ? i : (i - st.top() - 1)));
是如何計算當前矩形面積的,height[cur]明顯是當前矩形的高度,當前矩形的長度是(i - 1)- st.top() (想想爲什麼),具體代碼如下:class Solution {
public:
int largestRectangleArea(vector<int> &height) {
int res = 0;
stack<int> st;
height.push_back(0);//把0壓入棧,爲處理最後一個元素用的小技巧
for (int i = 0; i < height.size(); ++i) {
if (st.empty() || height[st.top()] < height[i]) {
st.push(i);
} else {
int cur = st.top(); st.pop();
res = max(res, height[cur] * (st.empty() ? i : (i - st.top() - 1)));
--i;
}
}
return res;
}
};
還找到一種不需要棧的方法,思想跟上面類似,也是找到局部最大值,只是沒用到棧:
class Solution {
public:
int largestRectangleArea(vector<int> &height) {
int res = 0;
for (int i = 0; i < height.size(); ++i) {
if (i + 1 < height.size() && height[i] <= height[i + 1]) {
continue;
}
int minH = height[i];
for (int j = i; j >= 0; --j) {// ///
minH = min(minH, height[j]);
int area = minH * (i - j + 1);
res = max(res, area);
}
}
return res;
}
};
感覺這種方法還是沒有上面一種優秀,j每次都是搜索到0的(第10行),其實根本不用搜索到0,這時,用棧的優勢就體現出來了。