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.
tags: array, stack, hash table, dynamic programming
很烦leetcode的一点就是,大部分题都不给时间复杂度和空间复杂度的要求。还得自己一点点来试。
这也是我见到的tag最多的一题,难度也为hard。
先写了暴力的O(nm)^2的算法,超时。
版本一:暴力搜索,O((nm)^2)。超时
class Solution { public: /** * assume the size of 2D array is n*m. * this is a brute violent algorithm with the O((nm)^2) time complexity. * **/ int maximalRectangle(vector<vector<char> > &matrix) { //handle empty input if(matrix.empty()){ return 0; } int maxArea = 0; int height = matrix.size(); int length = matrix[0].size(); //(sx, sy) is the left-top corner of a possible rectangle for(int sy = 0; sy < height; sy++){ for(int sx = 0; sx < length; sx++){ if(matrix[sy][sx] == '1'){ //(x,y) is the right-bottom corner of a possible rectangle int maxLength = length; for(int y = sy; y < height; y++){ for(int x = sx; x < length; x++){ if(matrix[y][x] == '0' || x - sx + 1 == maxLength){ //update maxLength maxLength = x - sx + 1; int thisArea = (x - sx + 1) * (y - sy + 1); maxArea = max(maxArea, thisArea); } } } } } } return maxArea; } };
我想写分治算法的,就是分别求出子区域的最大矩形面积,然后再求邻接边界的最大矩形面积,再拼出一个跨边界的矩形,算三者的最大值。但感觉很麻烦,尤其是拼矩形时的算法。
看了discussion,有人晒出了O(nm)的代码。利用了stack,并压缩了原始矩阵,还在学习中,稍候更新。
一月二十四日更新
版本二:o(mn). 动态规划,栈。
这个版本有点奇技淫巧。不够clean,但是能AC,还在尝试优化。
新建一个与原题一样大小的矩阵,每个单元格表示,从包括该单元格开始向上查的连续的1的个数。
也就是变成了矩形高度的直方图。
1010 1010 1011 => 2021 1011 => 3032 1111 4143
建完该矩阵后,开始扫每一行。并维护一个栈。栈里存储的是,可能的最大矩形的左下角的位置。算法保证了栈中的元素是递增的。当扫到每行的末尾时,计算栈里每个元素代表的矩阵大小,把栈清空。
比较难理解,这个方法不够清晰。尝试优化中。
更新:
原来这个是有特定算法的。求直方图中的最大面积:
http://blog.csdn.net/havenoidea/article/details/11854723
那这个算法就不算是奇技淫巧了阿~~哇哈哈。AC
class Solution { public: /** * O(nm) **/ int maximalRectangle(vector<vector<char> > &matrix) { if(matrix.empty()){ return 0; } int height = matrix.size(); int length = matrix[0].size(); int maxArea = 0; //s stores possible left-bottom start corner. stack<int> s; //map stores the current rectangle height of current column. int map[height][length]; for(int i = 0; i < length; i++){ map[0][i] = matrix[0][i] == '1'?1:0; } for(int j = 1; j < height; j++){ for(int i = 0; i < length; i++){ map[j][i] = matrix[j][i] == '1'?map[j - 1][i] + 1:0; } } for(int i = 0; i < height; i++){ int j = 0; while(j != length){ if(s.empty()){ s.push(j); j++; } //s is not empty else{ if (map[i][j] >= map[i][s.top()]){ s.push(j); j++; } //map[i][j] < the top of stack else{ while(map[i][j] < map[i][s.top()]){ int t = s.top(); s.pop(); int start = s.empty()?-1:s.top(); int thisArea = map[i][t] * (j - start - 1); maxArea = max(thisArea, maxArea); if (s.empty()){ break; } } //push j into the stack, now map[i][j] >= the top of stack } } } // j == length , at the end of the row while(!s.empty()){ int t = s.top(); s.pop(); int start = s.empty()?-1:s.top(); int thisArea = map[i][t] * (length - start - 1); maxArea = max(thisArea, maxArea); } } return maxArea; } };