美文网首页算法学习
算法题--求最大矩形面积

算法题--求最大矩形面积

作者: 岁月如歌2020 | 来源:发表于2020-04-24 16:37 被阅读0次
image.png

0. 链接

题目链接

1. 题目

Given n non-negative integers representing the histogram's bar height where the width of each bar is 1, find the area of largest rectangle in the histogram.

示意图

Above is a histogram where width of each bar is 1, given height = [2,1,5,6,2,3].

示意图

The largest rectangle is shown in the shaded area, which has area = 10 unit.

Example:

Input: [2,1,5,6,2,3]
Output: 10

2. 思路1:尝试以每个位置作为矩形的高, 再找到宽, 然后求出最大面积

  • 对于每个位置, 求出以这个位置为高的矩形中,宽度最宽的那一个矩形, 最后在所有最大矩形中,挑出最大面积
  • 对于任意位置i, 以heights[i]为高的矩形,左端lr分别为从i往左数的第一个小于heights[i]的下标,和从i往右数的第一个小于heights[i]的下标,有了这两个下标,就可以算出第i个矩形的面积了
  • 所以关键问题是,对于i,如何找到lr
  • 基本想法是从i往左往右遍历寻找,这样找到所有i对应的lr的复杂度为O(n^2),但实际上,我们可以记录并重用每个位置i对应的lr.
  • 记录lessFromLeft[i]表示从i往左数,第1个比heights[i]小的数字所处下标, lessFromRight[i]表示从i往右数,第1个比heights[i]小的数字所处下标,则可以看到,当求lessFromLeft[8]的时候, 可以用到lessFromFromLeft[7]的值, 然后求lessFromLeft[7]的时候, 可以用到lessFromLeft[6]的值, 以此类推, 直到lessFromLeft[1], 既然有这样的依赖关系,所以我们填充lessFromLeft的值的时候, 应该优先计算lessFromLeft[1]的值,然后接着计算下标更大的值; 同理, 应该优先计算lessFromRight[n - 2]的值, 然后接着计算下标更小的值.
  • 前面已经计算出了所有位置i处的lr,那么到这里就可以计算每个位置i处作为高的矩形的面积了,然后从这些面积可以得出最大面积。

3. 代码

# coding:utf8
from typing import List


class Solution:
    def largestRectangleArea(self, heights: List[int]) -> int:
        n = len(heights)
        min_values = [[0] * n for _ in range(n)]
        dp = [[0] * n for _ in range(n)]
        max_value = 0
        for i in range(n):
            for j in range(i, n):
                if j > i:
                    min_values[i][j] = min(min_values[i][j - 1], heights[j])
                else:
                    min_values[i][i] = heights[i]
                dp[i][j] = min_values[i][j] * (j - i + 1)
                max_value = max(max_value, dp[i][j])

        return max_value


class Solution1:
    def largestRectangleArea(self, heights: List[int]) -> int:
        n = len(heights)
        if n == 0:
            return 0

        less_from_left = [None] * n     # 每个元素往左数第一个小于该元素的位置
        less_from_right = [None] * n    # 每个元素往右数第一个小于该元素的位置
        less_from_left[0] = -1          # 特殊位置特殊处理, 方便后面计算宽度
        less_from_right[n - 1] = n      # 特殊位置特殊处理, 方便后面计算宽度

        for i in range(1, n):
            p = i - 1
            while p >= 0 and heights[p] >= heights[i]:
                p = less_from_left[p]   # 继续往左找第一个比heights[p]更小的元素
            less_from_left[i] = p       # 找到了i左边第一个比heights[i]更小的元素, 记录下来留给其他的i使用

        for i in range(n - 2, -1, -1):
            p = i + 1
            while p < n and heights[p] >= heights[i]:
                p = less_from_right[p]  # 继续往右边找第一个比heights[p]更小的元素
            less_from_right[i] = p      # 找到了i右边第一个比heights[i]更小的元素, 记录下来留给其他的i使用

        max_val = 0
        for i in range(n):
            # 计算以每个位置为高的矩形面积, 遴选出最大面积
            max_val = max(max_val, heights[i] * (less_from_right[i] - less_from_left[i] - 1))

        return max_val


def my_test(solution, heights):
    print('input: {}, output: {}'.format(heights, solution.largestRectangleArea(heights)))


solution = Solution1()
my_test(solution, [2, 1, 5, 6, 2, 3])
my_test(solution, [])

输出结果

input: [2, 1, 5, 6, 2, 3], output: 10
input: [], output: 0

4. 结果

image.png

相关文章

网友评论

    本文标题:算法题--求最大矩形面积

    本文链接:https://www.haomeiwen.com/subject/sfgfwhtx.html