leetcde-------求柱状图中最大的矩形(动态规划,中心扩展)

解法一:暴力枚举法:

思路:枚举出,每一列对应的最大矩形。最后找出最大的那个即可。

首先,要想找到第 i 位置最大面积是什么?

是以i 为中心,向左找第一个小于 heights[i] 的位置 left_i;向右找第一个小于于 heights[i] 的位置 right_i,即最大面积为 heights[i] * (right_i - left_i -1),如下图所示:

代码:

class Solution:
    def largestRectangleArea(self, heights: list) -> int:
        max_area = 0
        for i in range(len(heights)):
            left_i = i
            right_i = i
            while left_i >= 0 and heights[left_i] >= heights[i]:
                left_i -= 1
            while right_i < len(heights) and heights[right_i] >= heights[i]:
                right_i +=1
            area = heights[i]*(right_i-left_i-1)
            max_area = max(max_area,area)
            print('a={},i={},left={}.right={}'.format(area,i,left_i,right_i))
        return max_area

ss = Solution()
print(ss.largestRectangleArea([2,1,5,6,2,3]))  #10

时间复杂度:O(n^2)

空间复杂度:O(1)

解法二:暴力+动态规划(动态规划最小值求解)

为什么说是暴力法,因为这个解法也是要罗列出所有 i 位置矩形面积,从中选最大的。只是加入了动态规划的思想。

假设 dp[i][j]为位置从 i~j 的最小高度。则有:

dp[i][j]=min(height[j],dp[i][j-1])

代码一共两个循环,第一个循环,变量 i 取值0~n(n为输入列表的大小)。第二个循环,变量 j 取值 i~n。

依次计算矩阵(i~j)的面积。面积 = dp[i][j] * (j-i+1)

代码:

class Solution:
    def largestRectangleArea(self, heights: [int]) -> int:
        n = len(heights)
        max_area = 0
        dp = [[0 for i in range(n)] for j in range(n)]  #一般来说,没经过空间 优化的动态规划都会具备这么一个二维矩阵
        for i in range(n):
            for j in range(i,n):
                if i == j:
                    dp[i][j] = heights[i]
                elif heights[j] < dp[i][j-1]:
                    dp[i][j] = heights[j]
                elif heights[j] >= dp[i][j-1]:
                    dp[i][j] = dp[i][j-1]
                area = dp[i][j]*(j-i+1)
                max_area = max(max_area,area)
        return max_area
ss = Solution()
print(ss.largestRectangleArea([2,1,5,6,2,3]))  #10

时间复杂度:O(n^2)

空间复杂度:O(n^2)  因为数组 dp大小为 n*n
 

三,空间 优化后的动态规划

从解法二中我们可以看到,数组dp占的位置很多,而且dp中的值一般只被使用一次。所以dp可以用一个不断更新的变量代替。

class Solution:
    def largestRectangleArea(self, heights: [int]) -> int:
        n = len(heights)
        max_area = 0
        max_height = 0
        for i in range(n):
            for j in range(i,n):
                if i == j:
                    max_height = heights[i]
                elif heights[j] < max_height:
                    max_height = heights[j]
                area = max_height*(j-i+1)
                max_area = max(max_area,area)
        return max_area
ss = Solution()
print(ss.largestRectangleArea([2,1,5,6,2,3]))  #10

时间复杂度:O(n^2)

空间复杂度:O(1)

解法三,中心扩展法

对于每个柱子,考虑以当前柱高h作为矩形中的最大高度来构建矩阵。如果临近的柱子柱高比h更大,那么矩形可以向外侧扩展。

例如对于[4,2,3], i=2时,由于h[0] < h[1] > h[2],那么其左右端点可以延伸到left=0, right=2,即底长为2-0+1 = 3。
对于[4,2,1],i=2时,由于h[0] < h[1] , h[2] > h[0],那么左右端点为left=0, right=1,底长为1-0+1 = 2。

class Solution:
    def largestRectangleArea(self, heights: [int]) -> int:
        n = len(heights)
        max_area = 0
        for i in range(n):
            left = i
            right = i
            while left >0 and heights[left]>=heights[i]:
                left -= 1
            while right < n and heights[right]>=heights[i]:
                right +=1
            area = heights[i]*(right-left-1)
            max_area = max(max_area,area)
        return max_area
ss = Solution()
print(ss.largestRectangleArea([2,1,5,6,2,3]))  #10

时间复杂度:O(n^2)

空间复杂度:O(1)

发布了278 篇原创文章 · 获赞 470 · 访问量 82万+

猜你喜欢

转载自blog.csdn.net/u014453898/article/details/105120218