Maximal Rectangle

Date:

  Nov. 8, 2017.

Problem:

  https://leetcode.com/problems/maximal-rectangle/description/

Description:

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

  For example, given the following matrix:

    1 0 1 0 0

    1 0 1 1 1

    1 1 1 1 1

    1 0 0 1 0

  Return 6.

  容易分解出子问题:http://www.cnblogs.com/neopolitan/p/7783405.html。

  用heights列表记录矩阵某一行所有节点的高度,维护它。用子问题的函数求解即可。

  这个算法的复杂度为O(N^2)。以下为submission。

 1 class Solution:
 2     def maximalRectangle(self, matrix):
 3         if len(matrix) == 0:
 4             return 0
 5         col = len(matrix[0])
 6         heights = [0 for i in range(col)]
 7         res = 0
 8         for i in matrix:
 9             for j in range(col):
10                 if i[j] == '1':
11                     heights[j] += 1
12                 else:
13                     heights[j] = 0
14             res = max(res, self.largestRectangleArea(heights))
15         return res
16     def largestRectangleArea(self, heights):
17         stack = [-1]
18         rank = 0
19         result = 0
20         heights.append(0)
21         length = len(heights)
22         for i in range(length):
23             while rank > 0 and heights[i] <= heights[stack[rank]]:
24                 result = max(result, heights[stack[rank]] * (i - stack[rank - 1] - 1))
25                 stack.pop()
26                 rank -= 1
27             rank += 1
28             stack.append(i)
29         return result

  Alter:优雅的DP解法。

  考虑逐行分析每一点所在的可能的最大矩形,每次扫描使图的当前状态增加一行。

  假设我们现在在分析某一行,这时我们能从上一行继承某些信息来简化计算,例如,上一行的同一列的点可取得的最大高度。

  于是想象正在分析的这点向上取到最大高度,然后向左右取到最大宽度,获得这样一个可能的最大矩形。

  可以证明,这种方法不一定能取到某一点所在的最大矩形,但能取尽当前状态下所有可能的最大矩形。

  对于一个可能的最大矩形来说,它的四条边之外一定紧邻着至少一个0或者矩阵边界(考虑到我们是逐行扫描,它的底边一定紧邻着矩阵边界)。假设有一个最大矩形没有被我们取到,考虑它的顶边,当顶边外紧邻着一个0时,我们对这一列应用上面的方法,显然会取到这个最大矩形;当顶边紧邻着矩阵边界时,我们对矩形底边上的任意一点应用上面的方法,显然都会取到这个矩形。因此我们总是能取得当前状态下所有可能的最大矩形。

  于是我们维护三个数组,left,height和right。

  left记录按这一方法向左能取到的最大边界,它初始化为0。它可能直接向左取到最左边界,也可能继承上一行同一列的height,这取决于它所在的宽度能不能“装得下”之前宽度的矩形。归结起来,我们这样维护left:我们用一个current_left来记录当前可取的最左边界。当分析一点matrix[i, j]时,若matrix[i, j]为0,更新current_left为j;若matrix[i, j]不为0,我们对它进行取可能最大矩形的操作。left[j] = max(left[j], current _left)。

  right依葫芦画瓢。

  height记录按这一方法向上取到的最大边界。它的维护与上一种解法相似。遇0初始化为0,否则加1。

  扫描和维护的同时,我们维护一个maxrec来记录取得矩形的最大面积。

  这种算法的复杂度为O(N^2)。优雅度为O(N!)(

  以下是submission。

 1 class Solution:
 2     def maximalRectangle(self, matrix):
 3         if len(matrix) == 0:
 4             return 0
 5         col = len(matrix[0])
 6         height = [0 for i in range(col)]
 7         left = [0 for i in range(col)]
 8         right = [col for i in range(col)]
 9         res = 0
10         for i in matrix:
11             current_left = 0
12             current_right = col
13             for j in range(col):
14                 if i[j] == '0':
15                     height[j] = 0
16                     left[j] = 0
17                     current_left = j + 1
18                 else:
19                     height[j] += 1
20                     left[j] = max(left[j], current_left)
21             for j in range(col - 1, -1, -1):
22                 if i[j] == '0':
23                     right[j] = col
24                     current_right = j
25                 else:
26                     right[j] = min(right[j], current_right)
27                     res = max(res, (right[j] - left[j]) * height[j])
28         return res
原文地址:https://www.cnblogs.com/neopolitan/p/7806249.html