classSolution: deflargestRectangleArea(self, heights: List[int]) -> int: n, ans = len(heights), 0 if n != 0: ans = heights[0] for i in range(n): height = heights[i] for j in range(i, n): height = min(height, heights[j]) ans = max(ans, (j - i + 1) * height) return ans
复杂度分析
时间复杂度:$O(N^2)$
空间复杂度:$O(1)$
暴力枚举 - 中心扩展法(TLE)
思路
我们仍然暴力尝试所有可能的矩形。只不过我们这一次从中心向两边进行扩展。对于每一个 i,我们计算出其左边第一个高度小于它的索引 p,同样地,计算出右边第一个高度小于它的索引 q。那么以 i 为最低点能够构成的面积就是(q - p - 1) * heights[i]。 这种算法毫无疑问也是正确的。 我们证明一下,假设 f(i) 表示求以 i 为最低点的情况下,所能形成的最大矩阵面积。那么原问题转化为max(f(0), f(1), f(2), ..., f(n - 1))。
具体算法如下:
我们使用 l 和 r 数组。l[i] 表示 左边第一个高度小于它的索引,r[i] 表示 右边第一个高度小于它的索引。
我们从前往后求出 l,再从后往前计算出 r。
再次遍历求出所有的可能面积,并取出最大的。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
classSolution: deflargestRectangleArea(self, heights: List[int]) -> int: n = len(heights) l, r, ans = [-1] * n, [n] * n, 0 for i in range(1, n): j = i - 1 while j >= 0and heights[j] >= heights[i]: j -= 1 l[i] = j for i in range(n - 2, -1, -1): j = i + 1 while j < n and heights[j] >= heights[i]: j += 1 r[i] = j for i in range(n): ans = max(ans, heights[i] * (r[i] - l[i] - 1)) return ans
classSolution: deflargestRectangleArea(self, heights: List[int]) -> int: n = len(heights) l, r, ans = [-1] * n, [n] * n, 0
for i in range(1, n): j = i - 1 while j >= 0and heights[j] >= heights[i]: j = l[j] l[i] = j for i in range(n - 2, -1, -1): j = i + 1 while j < n and heights[j] >= heights[i]: j = r[j] r[i] = j for i in range(n): ans = max(ans, heights[i] * (r[i] - l[i] - 1)) return ans
复杂度分析
时间复杂度:$O(N)$
空间复杂度:$O(N)$
单调栈(Accepted)
思路
实际上,读完第二种方法的时候,你应该注意到了。我们的核心是求左边第一个比 i 小的和右边第一个比 i 小的。 如果你熟悉单调栈的话,那么应该会想到这是非常适合使用单调栈来处理的场景。
classSolution: deflargestRectangleArea(self, heights: List[int]) -> int: n, heights, st, ans = len(heights), [0] + heights + [0], [], 0 for i in range(n + 2): while st and heights[st[-1]] > heights[i]: ans = max(ans, heights[st.pop(-1)] * (i - st[-1] - 1)) st.append(i) return ans
CPP Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
classSolution { public: intlargestRectangleArea(vector<int>& A){ A.push_back(0); int N = A.size(), ans = 0; stack<int> s; for (int i = 0; i < N; ++i) { while (s.size() && A[s.top()] >= A[i]) { int h = A[s.top()]; s.pop(); int j = s.size() ? s.top() : -1; ans = max(ans, h * (i - j - 1)); } s.push(i); } return ans; } };
classSolution: deflargestRectangleArea(self, heights: List[int]) -> int: n, heights, st, ans = len(heights),[0] + heights + [0], [], 0 for i in range(n + 2): while st and heights[st[-1]] > heights[i]: a = heights[st[-1]] st.pop() # 如果没有前面的哨兵,这里的 st[-1] 可能会越界。 ans = max(ans, a * (i - 1 - st[-1])) st.append(i) return ans
classSolution: deflargestRectangleArea(self, heights: List[int]) -> int: n, heights, st, ans = len(heights), [0] + heights + [0], [], 0 for i in range(n + 2): while st and heights[st[-1]] > heights[i]: ans = max(ans, heights[st.pop(-1)] * (i - st[-1] - 1)) st.append(i)
return ans defmaximalRectangle(self, matrix: List[List[str]]) -> int: m = len(matrix) if m == 0: return0 n = len(matrix[0]) heights = [0] * n ans = 0 for i in range(m): for j in range(n): if matrix[i][j] == "0": heights[j] = 0 else: heights[j] += 1 ans = max(ans, self.largestRectangleArea(heights)) return ans
事实上,这道题还有空间复杂度 O(N)的解法,其中 N 指的是列数。 大家可以去这个leetcode 讨论看一下。
关键点解析
DP
递归公式可以利用 dp[i - 1][j]和 dp[i][j -1]的计算结果,而不用重新计算
空间复杂度可以降低到 O(n), n 为列数
代码
代码支持:Python,JavaScript:
Python Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
classSolution: defmaximalSquare(self, matrix: List[List[str]]) -> int: res = 0 m = len(matrix) if m == 0: return0 n = len(matrix[0]) dp = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(1, m + 1): for j in range(1, n + 1): dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1if matrix[i - 1][j - 1] == "1"else0 res = max(res, dp[i][j]) return res ** 2
classSolution: deflargestRectangleArea(self, heights: List[int]) -> int: n, heights, st, ans = len(heights), [0] + heights + [0], [], 0 for i in range(n + 2): while st and heights[st[-1]] > heights[i]: # 就只改了下面这一行 ans = max(ans, min(heights[st.pop()], (i - st[-1] - 1)) ** 2) st.append(i)
return ans
defmaximalSquare(self, matrix: List[List[str]]) -> int: m = len(matrix) if m == 0: return0 n = len(matrix[0]) heights = [0] * n ans = 0 for i in range(m): for j in range(n): if matrix[i][j] == "0": heights[j] = 0 else: heights[j] += 1 ans = max(ans, self.largestRectangleArea(heights)) return ans