diff --git a/solutions/221. Maximal Square.md b/solutions/221. Maximal Square.md index c8adac0..829d26c 100644 --- a/solutions/221. Maximal Square.md +++ b/solutions/221. Maximal Square.md @@ -39,6 +39,17 @@ 时间复杂度O(n^2), 空间复杂度O(n)。 +## 思路五、转换成求直方图包含的最大正方形 + +这题和[85. Maximal Rectangle](https://leetcode.com/problems/maximal-rectangle/)有点像,不同点就是85题只需要矩形而本题要求区域是正方形。如果把二维矩阵的第 i 行及上面的部分可以看成是一个直方图,那么85题又转化成了[84. Largest Rectangle in Histogram](https://leetcode.com/problems/largest-rectangle-in-histogram/)(见[85题思路一](85.%20Maximal%20Rectangle.md))。顺着这个思路,我们也可以利用84题来解此题。 + +具体来说,我们把二维矩阵的第 i 行及上面的部分可以看成是一个直方图(假设用数组hs表示),然后采用[84思路一](84.%20Largest%20Rectangle%20in%20Histogram.md)求出直方图里包含的最大正方形: +求出`hs[i]`向左第一个比他小的数`hs[j1]`和向右第一个比他小的数`hs[j2]`。那么此时能容纳的正方形的边长就为高和宽的较小者,即`min(heights[i], j2 - j1 - 1)`。 + +求数组中每个元素的左(右)边第一个比他大(小)的元素可利用单调栈在O(n)时间内求出,关于单调栈可以参考[我的总结](../algorithm/array/monotonic_stack_queue.md)。 + + +总的时间复杂度O(n^2), 空间复杂度O(n)。 ## 思路一 ``` C++ @@ -157,3 +168,47 @@ public: } }; ``` + +## 思路五 +``` C++ +class Solution { +private: + int helper(const vector&hs){ // 求直方图能容纳的最大正方形, 类似84题 + int n = hs.size(), max_l = 0; + vectorpre_smaller(n, -1), next_smaller(n, n); // 存的是下标 + stackstk1, stk2; // 存的也是下标 + + for(int i = 0; i < n; i++){ + while(!stk1.empty() && hs[stk1.top()] >= hs[i]) stk1.pop(); + if(!stk1.empty()) pre_smaller[i] = stk1.top(); + stk1.push(i); + + int j = n - i - 1; // 相当于反向遍历: for(int j = n-1; j >= 0; j--) + while(!stk2.empty() && hs[stk2.top()] >= hs[j]) stk2.pop(); + if(!stk2.empty()) next_smaller[j] = stk2.top(); + stk2.push(j); + } + + for(int i = 0; i < n; i++) + max_l = max(max_l, min(hs[i], next_smaller[i] - pre_smaller[i] - 1)); + + return max_l * max_l; + } +public: + int maximalSquare(vector>& matrix) { + if(matrix.empty()) return 0; + int m = matrix.size(), n = matrix[0].size(), res = 0; + + vectorhs(n, 0); + + for(int i = 0; i < m; i++){ + for(int j = 0; j < n; j++){ + if(matrix[i][j] == '1') hs[j]++; + else hs[j] = 0; + } + res = max(res, helper(hs)); + } + return res; + } +}; +```