首页 > 试题广场 >

最大矩形

[编程题]最大矩形
  • 热度指数:1626 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
给定一个仅包含 0 和 1 ,大小为 n*m 的二维二进制矩阵,找出仅包含 1 的最大矩形并返回面积。

数据范围: 保证输入的矩形中仅含有 0 和 1

例如输入[[1,0,1,0,0],[1,1,1,1,0],[1,1,1,1,1],[1,0,0,1,0]]时,对应的输出为8,所形成的最大矩形如下图所示:
示例1

输入

[[1]]

输出

1
示例2

输入

[[1,1],[0,1]]

输出

2

说明

第一列的两个 1 组成一个矩形    
示例3

输入

[[0,0],[0,0]]

输出

0
示例4

输入

[[1,0,1,0,0],[1,1,1,1,0],[1,1,1,1,1],[1,0,0,1,0]]

输出

8

单调栈(算法流程)

先做一个预处理,计算每个位置包括自己在内,往右有多少个连续的1。这样矩阵的每一列就都处理成了一个直方图。然后我们对矩阵的每一列都利用单调栈求一遍直方图内求最大矩形面积,从中选出最大的面积就可以了。
import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param matrix int整型二维数组 
     * @return int整型
     */
    public int maximalRectangle (int[][] matrix) {
        int n = matrix.length;
        int m = matrix[0].length;
        // 计算每个位置包括自己在内,右边有多少个连续的1
        for(int i = 0; i < n; i++){
            for(int j = m - 2; j >= 0; j--){
                matrix[i][j] = matrix[i][j] == 1? matrix[i][j] + matrix[i][j + 1]: 0;
            }
        }
        int maxArea = 0;
        int j = 0;
        while(j < m){
            int maxHeight = 0;
            int[] heights = new int[n];
            for(int k = 0; k < n; k++){
                heights[k] = matrix[k][j];
                maxHeight = Math.max(maxHeight, heights[k]);
            }
            if(maxHeight == 0) {
                j++;
                continue;
            }
            // 来一遍直方图内的最大矩形
            maxArea = Math.max(maxArea, largestRectangleArea(heights));
            j++;
        }
        return maxArea;
    }
    
    private int largestRectangleArea(int[] heights) {
        Stack<Integer> stack = new Stack<>();
        int maxArea = 0, n = heights.length;
        for(int i = 0; i < n; i++){
            while(!stack.isEmpty() && heights[i] < heights[stack.peek()]){
                int h = heights[stack.pop()];
                int L = stack.isEmpty()? 0: stack.peek() + 1;
                maxArea = Math.max(maxArea, h*(i - L));
            }
            stack.push(i);
        }
        while(!stack.isEmpty()){
            int h = heights[stack.pop()];
            int L = stack.isEmpty()? 0: stack.peek() + 1;
            maxArea = Math.max(maxArea, h*(n - L));
        }
        return maxArea;
    }
}

复杂度分析

预处理的时间复杂度为O(n*m),随后每一列都走“直方图内求最大矩形(单调栈时间复杂度O(n))”的算法流程,一共m列,因此整体的时间复杂度仍然为O(n*m)。
发表于 2021-12-23 13:10:22 回复(0)
/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 *
 * @param matrix int整型二维数组
 * @param matrixRowLen int matrix数组行数
 * @param matrixColLen int* matrix数组列数
 * @return int整型
 *
 * C语言声明定义全局变量请加上static,防止重复定义
 *
 * C语言声明定义全局变量请加上static,防止重复定义
 */
int maximalRectangle(int** matrix, int matrixRowLen, int* matrixColLen ) {
    // write code here
    int heights[*matrixColLen + 2];
    int stack[*matrixColLen + 2];
    int top = -1;
    int max = 0;
    heights[0] = 0;
    heights[*matrixColLen + 1] = 0;
    for (int j = 0; j < *matrixColLen + 2; j++) {
        heights[j] = 0;
    }
    for (int i = 0; i < matrixRowLen; i++) {
        //制作直方图
        heights[0] = 0;
        heights[*matrixColLen + 1] = 0;
        for (int j = 0; j < *matrixColLen; j++) {
            if (matrix[i][j] > 0)
                heights[j + 1] += matrix[i][j];
            else
                heights[j + 1] = 0;
        }
        //计算最大矩形
        for (int j = 0; j < *matrixColLen + 2; j++) {
            while (top != -1 && heights[j] <= heights[stack[top]]) {
                if (top == 0 && j < *matrixColLen + 1)
                    break;
                // 获取栈顶元素对应的高
                int curHeight = heights[stack[top--]];
                // 栈顶元素弹出后,新的栈顶元素就是其左侧边界
                int leftIndex = stack[top];
                // 右侧边界是当前考察的索引
                int rightIndex = j;
                // 计算矩形宽度
                int curWidth = rightIndex - leftIndex - 1;

                // 计算面积
                max = curWidth * curHeight > max ? curWidth * curHeight : max;
            }
            stack[++top] = j;
        }
    }
    return max;
}

发表于 2022-07-27 12:04:02 回复(0)
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param matrix int整型vector<vector<>> 
     * @return int整型
     */
    int maximalRectangle(vector<vector<int> >& matrix) {
        // write code here
        int maxArea = 0;
        
        int m = matrix.size();
        int n = matrix[0].size();
        
        for(int i = 0; i < m; ++i){
            for(int j = 0; j < n; ++j){
                if(matrix[i][j]){
                    if(j)
                        matrix[i][j] = matrix[i][j - 1] + 1;
                    int len = matrix[i][j];
                    int height = 1;
                    while(i - height + 1 >= 0 && matrix[i - height + 1][j]){
                        len = min(len, matrix[i - height + 1][j]);
                        maxArea = max(maxArea, len * height);
                        ++height;
                    }
                }
            }
        }
        
        return maxArea;
    }
};

发表于 2022-07-19 09:10:51 回复(0)
# -*- coding: utf-8 -*-


#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param matrix int整型二维数组
# @return int整型
#
class Solution:
    """
    题目:
        https://www.nowcoder.com/practice/5720efc1bdff4ca3a7dad37ca012cb60?tpId=196&tqId=39479&rp=1&ru=/exam/oj&qru=/exam/oj&sourceUrl=%2Fexam%2Foj%3FjudgeStatus%3D3%26page%3D1%26pageSize%3D50%26search%3D%26tab%3D%25E7%25AE%2597%25E6%25B3%2595%25E7%25AF%2587%26topicId%3D196&difficulty=undefined&judgeStatus=3&tags=&title=
    算法:
        1. 构建动态规划矩阵
            设dp[i][j]表示第i行以元素matrix[i][j]结尾的连续1的个数
            状态转移方程:
                若matrix[i][j] == 0:
                    dp[i][j] = 0
                否则:
                     dp[i][j] = 1 if j == 0 else dp[i][j - 1] + 1
        2. 遍历矩阵dp,对于dp[i][j],我们从第i行枚举到0行,不断计算以matrix[i][j]为右下角的最大矩形面积,并更新res
    复杂度:
        时间复杂度:O(mn)
        空间复杂度:O(mn)
    """

    def maximalRectangle(self, matrix):
        # write code here
        m, n = len(matrix), len(matrix[0])

        dp = [[0] * n for _ in range(m)]
        for i in range(m):
            if matrix[i][0] == 1:
                dp[i][0] = 1
        for i in range(m):
            for j in range(1, n):
                if matrix[i][j] == 1:
                    dp[i][j] = dp[i][j - 1] + 1
        # print dp

        res = 0
        for i in range(m):
            for j in range(n):
                if dp[i][j] == 0:
                    continue
                area, width = dp[i][j], dp[i][j]
                for k in range(i - 1, -1, -1):
                    width = min(width, dp[k][j])
                    area = max(area, width * (i - k + 1))
                res = max(res, area)
        return res


if __name__ == "__main__":
    sol = Solution()

    # matrix = [[1]]

    # matrix = [[1, 1], [0, 1]]

    # matrix = [[0, 0], [0, 0]]

    matrix = [[1, 0, 1, 0, 0], [1, 1, 1, 1, 0], [1, 1, 1, 1, 1], [1, 0, 0, 1, 0]]

    res = sol.maximalRectangle(matrix)

    print res

发表于 2022-07-03 13:14:58 回复(0)
窓头像
class Solution:
    def maximalRectangle(self, matrix):
        # 预处理,使每个元素的值表示从当前位置开始向上数,连续的1的个数
        for i in range(1, len(matrix)):
            for j in range(len(matrix[0])):
                matrix[i][j] = matrix[i - 1][j] + 1 if matrix[i][j] else matrix[i][j]
        maxRec = 0
        for line in matrix:
            for i in range(len(line)):
                # 对每个>0的元素,向左求他和左边的元素能组成的最大矩形,碰到0停止
                if line[i] > 0:
                    x = 0
                    j = i
                    minH = line[i]
                    while j >= 0 and line[j] > 0:
                        minH = min(minH, line[j])
                        x += 1
                        j -= 1
                        maxRec = max(maxRec, x * minH)
        return maxRec

发表于 2022-03-13 17:47:06 回复(0)
压缩矩阵
暴力求解的时间复杂度为 O(M^3*N^3)
该解法的时间复杂度为O(N^2*M)
从矩阵第一行开始到matrix[0].length行遍历矩阵
再从矩阵第二行开始到matrix[0].length行遍历矩阵
............一直到最后一行

用arr[]来存储矩阵的类加值

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param matrix int整型二维数组 
     * @return int整型
     */
    public int maximalRectangle (int[][] matrix) {
        // write code here
        int maxS=0;
        for(int i=0;i<matrix.length;i++){
            int[] arr=new int[matrix[0].length];
            for(int j=i,row=1;j<matrix.length;j++){
                int sum=0;
                for(int k=0;k<matrix[0].length;k++){
                    arr[k]+=matrix[j][k];
                    if(arr[k]==row){
                        sum+=arr[k];
                        maxS=Math.max(maxS,sum);
                    }else{
                        sum=0;
                    }
                }
                row++;
            }
        }
        return maxS;
    }
}


发表于 2022-03-08 16:16:49 回复(0)
class Solution:
    def maximalRectangle(self , matrix: List[List[int]]) -> int:
        # write code here

        m = len(matrix)
        if not m:
            return 0
        n = len(matrix[0])
        dp = [0]*n
        ans = 0
        for i in range(m):
            for j in range(n):
                dp[j] = 0 if matrix[i][j] == 0 else dp[j]+1
            ans = max(ans,self.compute_Area(dp))
        return ans

    def compute_Area(self,heights):
        stack = [(-1,-1)]
        H = heights+[0]
        ans = 0
        for i,h in enumerate(H):
            while stack[-1][1]>h:
                _,oh = stack.pop()
                s = (i-stack[-1][0]-1)*oh
                ans = max(ans,s)
            stack.append((i,h))
        return ans



发表于 2022-02-17 16:17:51 回复(0)