本來並無重視這個技巧,可是後來回過頭再來作幾道關於DP的題目,意外地發現這個作法能夠將O(n^2)的複雜度優化至O(n)!因此打算將這類題目作一個總結吧。bash
Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.優化
For example, given height = [2,1,5,6,2,3].ui
The largest rectangle area is 10 unit.spa
基本思想:用棧維護一個遞增子序列3d
爲了方便記錄矩形的寬度,咱們在棧中存放的是矩形的下標。code
咱們用 i
遍歷全部的矩形,當棧尾元素 j
對應的矩形高度大於或等於當前遍歷到的矩形時(出現了局部非遞增),能夠保證:前面出現的上升序列中可能存在最大面積。以下圖:cdn
這樣當遇到局部遞減時,依次取出棧尾,若是 s
未空面積 area = height[cur] * (i-s.top()-1)
就是棧尾元素對應的高度乘以跨度,若是此時s已空, area = height[cur] * i
。blog
最後須要注意,爲防止全是單調上升的狀況致使 s
沒法清空,能夠增設一個高度爲 0 的矩形。ip
class Solution {
public:
/** * @param height: A list of integer * @return: The area of largest rectangle in the histogram */
int largestRectangleArea(vector<int> &height) {
int result = 0;
height.push_back(0);
stack<int> s;
for (int i = 0; i < height.size(); ++i) {
while (!s.empty() && height[s.top()] >= height[i]) {
int cur = s.top(), area;
s.pop();
if (s.empty()) area = height[cur] * i;
else area = height[cur] * (i-s.top()-1);
result = max(result, area);
}
s.push(i);
}
return result;
}
};
複製代碼
給你一個二維矩陣,權值爲False和True,找到一個最大的矩形,使得裏面的值所有爲True,輸出它的面積get
好比,給你一個矩陣以下
1 1 0 0 1
0 1 0 0 1
0 0 1 1 1
0 0 1 1 1
0 0 0 0 1
複製代碼
答案是6
先用相似前綴和的作法先預處理原矩形,在縱向上來看,全部的1能夠類加成高度
1 1 0 0 1
0 2 0 0 2
0 0 1 1 3
0 0 2 2 4
0 0 0 0 5
複製代碼
因而能夠在O(1)的時間裏得到當前行的矩形高度,而後用相似「直方圖最大矩形面積」的作法求出每一行段的最大面積,就能夠找出最大值。
綜上,時間複雜度O(n^2)
class Solution {
private:
int getLayerMax(vector<int> &height) {
int _max = 0, size = height.size();
stack<int> s;
height.push_back(0);
for (int i = 0; i < height.size(); ++i) {
while (!s.empty() && height[i] <= height[s.top()]) {
int cur = s.top();
s.pop();
if (s.empty()) _max = max(_max, height[cur]*i);
else _max = max(_max, height[cur]*(i-s.top()-1));
}
s.push(i);
}
return _max;
}
public:
int maximalRectangle(vector<vector<bool> > &matrix) {
if (matrix.empty() || matrix[0].empty()) return 0;
int m = matrix.size(), n = matrix[0].size(), _max = 0;
vector<vector<int> > prefix(m, vector<int>(n, 0));
for (int j = 0; j < n; ++j)
for (int i = 0; i < m; ++i)
if (!matrix[i][j]) prefix[i][j] = 0;
else prefix[i][j] = (i==0) ? 1 : prefix[i-1][j] + 1;
for (int i = 0; i < m; ++i)
_max = max(_max, getLayerMax(prefix[i]));
return _max;
}
};
複製代碼