leetcode85.最大矩形

题目链接:https://leetcode.cn/problems/maximal-rectangle/

思路

将矩阵拆分成若干个柱状图,然后直接复用84.柱状图中最大的矩形的解法。

假设有以下矩阵:
在这里插入图片描述
矩阵前1行形成的柱状图:1 0 1 0 0
在这里插入图片描述
矩阵前2行形成的柱状图:2 0 2 1 1
在这里插入图片描述
矩阵前3行形成的柱状图:3 1 3 2 2
在这里插入图片描述
矩阵前4行形成的柱状图:4 0 0 3 0
在这里插入图片描述
对每个柱状图调用maxArea求最大矩形面积,取所有面积的最大值即为所求。

Java

class Solution {
    public int maximalRectangle(char[][] matrix) {
        if (matrix.length == 0) {
            return 0;
        }

        int[] nums = new int[matrix[0].length];
        int result = 0;

        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[i].length; j++) {
                nums[j] = matrix[i][j] == '1' ? nums[j] + 1 : 0;
            }
            result = Math.max(result, maxArea(nums));
        }

        return result;
    }

    // 参见 https://leetcode.cn/problems/largest-rectangle-in-histogram/
    private int maxArea(int[] nums) {
        // left[i]表示nums[i]左边第一个小于nums[i]的元素下标
        int[] left = new int[nums.length];
        left[0] = -1;
        for (int i = 1; i < nums.length; i++) {
            int j = i - 1;
            while (j != -1 && nums[j] >= nums[i]) {
                j = left[j];
            }
            left[i] = j;
        }

        // right[i]表示nums[i]右边第一个小于nums[i]的元素下标
        int[] right = new int[nums.length];
        right[nums.length - 1] = nums.length;
        for (int i = nums.length - 2; i >= 0; i--) {
            int j = i + 1;
            while (j != nums.length && nums[j] >= nums[i]) {
                j = right[j];
            }
            right[i] = j;
        }

        int result = 0;
        for (int i = 0; i < nums.length; i++) {
            result = Math.max(result, nums[i] * (right[i] - left[i] - 1));
        }

        return result;
    }
}

Go

func maximalRectangle(nums [][]byte) int {
	if len(nums) == 0 {
		return 0
	}

	max := func(a, b int) int {
		if a > b {
			return a
		}
		return b
	}

	// 参见 https://leetcode.cn/problems/largest-rectangle-in-histogram/
	maxAreaOfRow := func(nums []int) int {
		// left[i]表示nums[i]左边第一个比nums[i]小的元素下标
		left := make([]int, len(nums))
		left[0] = -1
		for i := 1; i < len(nums); i++ {
			idx := i - 1
			for idx != -1 && nums[idx] >= nums[i] {
				idx = left[idx]
			}
			left[i] = idx
		}

		// right[i]表示nums[i]右边第一个比nums[i]小的元素下标
		right := make([]int, len(nums))
		right[len(nums)-1] = len(nums)
		for i := len(nums) - 2; i >= 0; i-- {
			idx := i + 1
			for idx != len(nums) && nums[idx] >= nums[i] {
				idx = right[idx]
			}
			right[i] = idx
		}

		maxArea := 0
		for i := 0; i < len(nums); i++ {
			maxArea = max(maxArea, nums[i]*(right[i]-left[i]-1))
		}

		return maxArea
	}

	row := make([]int, len(nums[0]))
	maxArea := 0
	for i := 0; i < len(nums); i++ {
		for j := 0; j < len(nums[i]); j++ {
			if nums[i][j] == '0' {
				row[j] = 0
			} else {
				row[j]++
			}
		}
		maxArea = max(maxArea, maxAreaOfRow(row))
	}

	return maxArea
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

byx2000

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值