LeetCode Maximal Rectangle

Maximal Rectangle

Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing all ones and return its area.


一道超难的题目,思想难,同时实现也难。

本题是动态规划法的高级应用,还依据题目特征优化,难度相当高。


经提示,知道是max histogram这个题目的思想的灵活运用,就是每一行运用max histogram算法思想计算。

原来LeetCode把max histogram放在这一题之前是有原因的。没有max histogram这一题的思想基础垫底,是很难理解的。

LeetCode论坛上的讨论,其实也是这一思想的变种运用,不过感觉讲得并不清楚,他所谓的拖线法,其实就是histogram的倒置。

只不过并没有严格按照histogram的算法来进行,而是优化了。

我按histogram算法写的程序用了大概100ms左右,他的算法程序能在40-50ms左右,很快。

所以我也不得不研究一下他的算法到底优化了什么。

他使用了三个表L,R,H表,我也画了三个表,对比看看,填填这个表,就能理解这个算法了:

LeetCode Maximal Rectangle_第1张图片

下面是标准的histogram题目算法的应用程序:

[cpp]  view plain copy print ?
  1. class Solution {  
  2. public:  
  3.     int maximalRectangle(vector<vector<char> > &matrix)   
  4.     {  
  5.         int row = matrix.size();  
  6.         if (row < 1) return 0;  
  7.         int col = matrix[0].size();  
  8.         vector<int> his(col);  
  9.         int maxArea = 0;  
  10.   
  11.         for (int i = row-1; i >= 0; i--)  
  12.         {  
  13.             formHistogram(matrix, i, his);  
  14.             maxArea = max(maxArea, maxHistogram(his));  
  15.         }  
  16.         return maxArea;  
  17.     }  
  18.   
  19.     void formHistogram(vector<vector<char> > &m, int row, vector<int> &his)  
  20.     {  
  21.         for (size_t j = 0; j < m[0].size(); j++)  
  22.         {  
  23.             if (m[row][j]-'0' == 0) his[j] = 0;  
  24.             else if (row != m.size()-1 && m[row+1][j]-'0' == 1)  
  25.             {  
  26.                 his[j]--;  
  27.             }  
  28.             else  
  29.             {  
  30.                 for (int i = row; i >= 0; i--)  
  31.                 {  
  32.                     if (m[i][j]-'0' == 1) his[j]++;  
  33.                     else break;  
  34.                 }  
  35.             }  
  36.         }  
  37.     }  
  38.     int maxHistogram(vector<int> &h)  
  39.     {  
  40.         h.push_back(0);  
  41.         int n = h.size();  
  42.         int maxArea = 0;  
  43.         stack<int> stk;  
  44.   
  45.         for (int i = 0; i < n; )  
  46.         {  
  47.             if (stk.empty() || h[stk.top()] <= h[i]) stk.push(i++);  
  48.             else  
  49.             {  
  50.                 int t = stk.top();  
  51.                 stk.pop();  
  52.                 maxArea = max(maxArea, h[t]*(stk.empty()? i:i-stk.top()-1));  
  53.             }  
  54.         }  
  55.         return maxArea;  
  56.     }  
  57. };  

优化一点histogram算法的程序:

[cpp]  view plain copy print ?
  1. int maxHistogram(vector<int> &h)  
  2.     {  
  3.         h.push_back(0);  
  4.         int n = h.size();  
  5.         int maxArea = 0;  
  6.         stack<int> stk;  
  7.   
  8.         for (int i = 0; i < n; )  
  9.         {  
  10.             if (stk.empty() || h[stk.top()] <= h[i]) stk.push(i++);  
  11.             else  
  12.             {  
  13.                 int t = stk.top();  
  14.                 stk.pop();  
  15.                 maxArea = max(maxArea, h[t]*(stk.empty()? i:i-stk.top()-1));  
  16.             }  
  17.         }  
  18.         return maxArea;  
  19.     }  
  20.     //================histogram,拖线法实现  
  21.     int maximalRectangle2(vector<vector<char> > &matrix)   
  22.     {  
  23.         int row = matrix.size();  
  24.         if (row < 1) return 0;  
  25.         int col = matrix[0].size();  
  26.         vector<int> his(col);  
  27.         int maxArea = 0;  
  28.   
  29.         for (int i = row-1; i >= 0; i--)  
  30.         {  
  31.             for (int j = 0; j < col; j++)  
  32.             {  
  33.                 if ( matrix[i][j]-'0' == 1) his[j]++;  
  34.                 else his[j] = 0;  
  35.             }  
  36.   
  37.             maxArea = max(maxArea, maxHistogram(his));  
  38.         }  
  39.         return maxArea;  
  40.     }  

最后是leetcode上的优化算法,也是上图示意图的算法实现:

[cpp]  view plain copy print ?
  1. int maximalRectangle(vector<vector<char> > &matrix) {  
  2.         if (matrix.empty()) {  
  3.             return 0;  
  4.         }  
  5.   
  6.         int n = matrix[0].size();  
  7.         vector<int> H(n);  
  8.         vector<int> L(n);  
  9.         vector<int> R(n, n);  
  10.   
  11.         int ret = 0;  
  12.         for (int i = 0; i < matrix.size(); ++i) {  
  13.             int left = 0, right = n;  
  14.             // calculate L(i, j) from left to right  
  15.             for (int j = 0; j < n; ++j) {  
  16.                 if (matrix[i][j] == '1') {  
  17.                     ++H[j];  
  18.                     L[j] = max(L[j], left);  
  19.                 }  
  20.                 else {  
  21.                     left = j+1;  
  22.                     H[j] = 0; L[j] = 0; R[j] = n;  
  23.                 }  
  24.             }  
  25.             // calculate R(i, j) from right to right  
  26.             for (int j = n-1; j >= 0; --j) {  
  27.                 if (matrix[i][j] == '1') {  
  28.                     R[j] = min(R[j], right);  
  29.                     ret = max(ret, H[j]*(R[j]-L[j]));  
  30.                 }  
  31.                 else {  
  32.                     right = j;  
  33.                 }  
  34.             }  
  35.         }  
  36.   
  37.         return ret;  
  38.     }  

2014-2-27 update:

还是下面这个程序比较保险,虽然leetcode上测试,是上一个程序比较快,但是按照理论上计算,两个算法的时间复杂度都是O(n*n),而空间复杂度也都是O(n),那么其实两个方法的实际运行速度都应该差不多的。

而且主要是下面这个程序更加模块化,更简易;上一个程序很容易出错,下标处理起来很麻烦的,一不小心结果就会出错。

[cpp]  view plain copy print ?
  1. int maximalRectangle(vector<vector<char> > &matrix)   
  2.     {  
  3.         if (matrix.empty() || matrix[0].empty()) return 0;  
  4.         vector<int> height(matrix[0].size()+1);  
  5.         int max_area = 0;  
  6.         for (int i = 0; i < matrix.size(); i++)  
  7.         {  
  8.             for (int j = 0; j < matrix[0].size(); j++)  
  9.             {  
  10.                 if (matrix[i][j] == '1') height[j]++;  
  11.                 else height[j] = 0;  
  12.             }  
  13.             max_area = max(max_area, maxHistogram(height));  
  14.         }  
  15.         return max_area;  
  16.     }  
  17.     int maxHistogram(vector<int> &height)  
  18.     {  
  19.         int ans = 0;  
  20.         stack<int> stk;  
  21.         for (int i = 0; i < height.size(); )  
  22.         {  
  23.             if (stk.empty() || height[stk.top()] < height[i]) stk.push(i++);  
  24.             else  
  25.             {  
  26.                 int idx = stk.top();  
  27.                 stk.pop();  
  28.                 ans = max(ans, (stk.empty()? i:i-stk.top()-1)*height[idx]);  
  29.             }  
  30.         }  
  31.         return ans;  
  32.     }  

你可能感兴趣的:(LeetCode Maximal Rectangle)