85. Maximal Rectangle
来源:互联网 发布:单片机串口通信原理 编辑:程序博客网 时间:2024/06/16 07:08
Given a 2D binary matrix filled with 0's and 1's, find the largest rectangle containing all ones and return its area.
一道hard题,但没有规定复杂度要求,所以我先用最基本的方法做了遍。对比在一个一位数组求直方图最大面积问题,每个数对应的可以有的最大面积是以它为最小值的最长序列,所以,找到一个标准开始循环就行。
方法一:暴力循环,O(n^4)
我选的标准就是逐个扫描点,考虑它作为矩形左上角对应的最大矩形面积。当发现1时,外循环停下,开始从这个店向右向下找。假设整个matrix是n*n,这种做法复杂度就是O(n^4), 虽然low了点,但是leetcode还是可以接受的,然而我自己做也就会这么写了。如下:
int maximalRectangle(vector<vector<char>>& matrix) { int H = matrix.size(); if (H == 0) return 0; int W = matrix[0].size(); int i, j, tempi, tempj, tempW;//i,j代表大循环坐标,tempi,tempj代表找矩形的小循环坐标 int area, maxrect=0; for (i = 0; i < H; i++) { for (j = 0; j < W; j++) { // 找到1之后以它为左上角搜索最大面积 if (matrix[i][j] == '1') { tempW = W; for (tempi = i; tempi < H; tempi++) { if (matrix[tempi][j] == '1') { // 换行后如果首字不是1,直接break for (tempj = j; tempj < tempW; ) { if (matrix[tempi][tempj] == '0') break; else tempj++; } // 更新宽度右边界 tempW = min(tempW, tempj); // 搜索完每行更新一下最大面积 area = (tempi - i + 1) * (tempj - j); maxrect = max(maxrect, area); } else break; } } } } return maxrect;}
方法二:动态规划优化,复杂度O(n^3)
同样的思路,但不用每次都向右向下循环。可以先建一个表,存下从这点开始,这一行还能连续有几个1。
然后大循环遇到1停下来只用向下找就可以了。
int maximalRectangle(vector<vector<char>>& matrix) { int H = matrix.size(); if (H == 0) return 0; int W = matrix[0].size(); vector<vector<int>> dp(H, vector<int>(W)); int i, j, tempi, tempW; int maxrect = 0, area; // 初始化dp矩阵 for (i = 0; i < H; i++) dp[i][W - 1] = (matrix[i][W - 1] == '1'); for (i = 0; i < H; i++) for (j = W - 2; j >= 0; j--) { if (matrix[i][j] == '1') dp[i][j] = 1 + dp[i][j + 1]; else dp[i][j] = 0; } // 枚举所有点,同样作为左上角 for (i = 0; i < H; i++) { for (j = 0; j < W; j++) { // 预判,如果此时最大可能面积都不够,直接结束这一行 if ((H - i)*(W - j) < maxrect) break; tempW = dp[i][j]; for (tempi = i; tempi < H && tempW > 0; tempi++) { // 随着最小宽度的变化,可是适时终止判断 if (tempW > dp[tempi][j]) tempW = dp[tempi][j]; if (tempW * (H - i) < maxrect) break; area = tempW * (tempi - i + 1); maxrect = max(area, maxrect); } } } return maxrect;}
这里有两次预判可以注意下,适当的减少了很多不必要的判断。如果当前最大的可能性都不比现有的最大面积大的话,不需要徒劳循环,方法一时间上超过10%,方法二超过了70%,其实基本思路已经get了,但差别就是这么大。
方法三:将二维问题回归一维,O(n^2)
这个厉害了,虽然我也想到了联系之前的直方图找最大面积, largest Rectangle in histogram, 这里可以每一行看做一个直方图,用方法二建表的思想可以先建立一个二维的height矩阵,每一行代表从这一行向上可以有的连续1的个数,然后这一行就是一个直方图问题,然后就可以用stack实现O(n)复杂度的面积,然后循环每一行就可以。简直棒呆!
class Solution {public:// 一维数组直方图最大面积的线性方法应该熟悉int largestRectangleArea(vector<int>& height) { if (height.size() == 0) return 0; height.push_back(0); // 结尾加0 int i, maxrect = 0, temp; stack<int> s; for (i = 0; i < height.size(); ) { if (s.empty() || height[i] >= height[s.top()]) { s.push(i); i++; } //保持递增序列,遇到右边界弹出计算 else { temp = s.top(); s.pop(); if (s.empty()) maxrect = max(maxrect, height[temp] * i);//没有左边界就直接是现有长度乘它 else maxrect = max(maxrect, height[temp] * (i - s.top() - 1));//有左边界就算长度 } } return maxrect;}int maximalRectangle(vector<vector<char>>& matrix) { int H = matrix.size(); if (H == 0) return 0; int W = matrix[0].size(); vector<vector<int> > height(H, vector<int>(W, 0)); int i, j, maxrect = 0; // 将每一行都构造成一个直方图 for (i = 0; i < H; i++) { for (j = 0; j < W; j++) { if (matrix[i][j] == '0') height[i][j] = 0; else height[i][j] = (i == 0) ? 1 : (height[i - 1][j] + 1); } } // 用之前算法解决每一行的最大面积 for (i = 0; i < H; i++) { maxrect = max(maxrect, largestRectangleArea(height[i])); } return maxrect;}};
总之,这一题在我自己做了O(n^4)的解法后,学习了更优化的两种写法,确实感慨不已。
1 0
- LeetCode 85. Maximal Rectangle
- [Leetcode] 85. Maximal Rectangle
- LeetCode --- 85. Maximal Rectangle
- [LeetCode]*85.Maximal Rectangle
- 85. Maximal Rectangle
- [leetcode] 85.Maximal Rectangle
- Leetcode 85. Maximal Rectangle
- 85. Maximal Rectangle
- leetcode 85. Maximal Rectangle
- LeetCode 85. Maximal Rectangle
- Leetcode 85. Maximal Rectangle
- Leetcode:85. Maximal Rectangle
- LeetCode 85. Maximal Rectangle
- LeetCode-85.Maximal Rectangle
- leetcode.85. Maximal Rectangle
- 85. Maximal Rectangle
- leetcode 85. Maximal Rectangle
- 85. Maximal Rectangle
- Android 微博分享及其注意事项
- 关于PowerImageView使用问题总结
- javascript
- Codeforces Round #362 (Div. 1) B Puzzles
- poj 2115扩展欧几里得总结
- 85. Maximal Rectangle
- Android GridView设置宽高,即item宽度高度
- 总有一个在路上
- 日积(Running)月累(ZSSURE):nginx配置、putty连接保持以及AngularJS作用域$scope
- STM32 IAP(在线更新程序)的使用关键点
- 解决未知视频广告导入问题
- Android入门——数据存储之SharedPreferences详解与应用
- 判断用户是安卓还是ios的php代码
- 二叉树的按层遍历