思路
雖然這是一個二維矩陣的問題,但是能拆解成一系列的一維問題來想。 假設現在的矩陣是
- 第一列的高度是
- 第二列的高度是
- 第三列的高度是
在知道高度之後,就能夠找出從「各列看」的最大矩形面積。
如果現在給定的高度是
從 往外擴張,
- 左邊遇到數字 比自己小,所以左邊界在 。
- 右邊遇到數字 比自己大,繼續往右,遇到比自己小的 。
這時高度為 的矩形面積,最大就是 * (右邊界 - 左邊界 - ) = (邊界左開右開)
如果每個數字都往外擴張去找邊界,需要花 的時間,因此需要優化。
優化的方式用單調棧。(紀錄位置)
以剛才的高度為例,一開始棧為空,
, ,
,,這時 彈出,也就得知了 的右邊界 ,
因為棧為空, 的左邊界是 (左開右開),參考答案 ,
最後
, 的位置,沒有彈出,。
, 的位置,沒有彈出,。
, 的位置,連續彈出兩次。
-
彈出(對應到 6):
右邊界 ,左邊界
參考答案 -
彈出(對應到5):
右邊界 ,左邊界
參考答案
後面以此類推,就能算出這一列高度的最大矩形面積。
程式碼
單調棧
class Solution {
private:
int helper(vector<int> heights) {
heights.push_back(0); // 加入一個 0, 方便計算
int m = heights.size();
int res = 0;
stack<int> stk; // 紀錄位置
for(int i = 0; i < m; ++i) { // 最後的 0 會把所有的內容 pop 掉
while(!stk.empty() && heights[stk.top()] > heights[i]) {
int h = heights[stk.top()];
int pos = stk.top();
stk.pop();
int left = stk.empty() ? -1 : stk.top(); // 左邊界
int width = i - left - 1; // 左開右開
res = max(res, h * width);
}
stk.push(i);
}
return res;
}
public:
int maximalRectangle(vector<vector<char>>& matrix) {
int n = matrix.size(), m = matrix[0].size();
vector<int> heights(m);
int res = 0;
for(int i = 0; i < n; ++i) {
for(int j = 0; j < m; ++j) {
// 如果是 1, 接續上一層, 如果是 0, 長條圖斷掉, 歸零
heights[j] = matrix[i][j] == '1' ? heights[j] + 1 : 0;
}
res = max(res, helper(heights));
}
return res;
}
};
複雜度分析
- 時間複雜度:
- 空間複雜度: