第七周算法作业

本文介绍了LeetCode中两道经典算法题的解决方案,分别是最大矩形问题和乘积最大子数组问题。最大矩形问题利用单调栈求解每个柱子所能构成的最大矩形面积,而乘积最大子数组问题通过动态规划找到数组中乘积最大的连续子数组。详细解析了算法思路和代码实现,适合进阶学习。
摘要由CSDN通过智能技术生成

第七周算法作业 No.85,152

85. 最大矩形

  • 思路

    此题基于第84题,所以先讲解84题的思路,再回到本题
    84题的链接为: https://leetcode-cn.com/problems/largest-rectangle-in-histogram/
    在这里插入图片描述

  • 84题
    采用的方法是单调栈
    整体思路是对每个柱子求解该柱子能够容纳的最大矩形,需要分别计算左边第一个比当前柱子矮的下标以及右边第一个比当前柱子矮的下标。
    在这里插入图片描述

  • 例子

    我们用一个具体的例子[6, 7, 5, 2, 4, 5, 9, 3]来理解单调栈。我们需要求出每一根柱子的左侧且最近的小于其高度的柱子。初始时的栈为空。

    我们枚举 6,因为栈为空,所以 6 左侧的柱子是「哨兵」,位置为 -1。随后我们将 6 入栈。

    栈:[6(0)]。(这里括号内的数字表示柱子在原数组中的位置)
    我们枚举 7,由于 6<7,因此不会移除栈顶元素,所以 7 左侧的柱子是 6,位置为 0。随后我们将 7 入栈。

    栈:[6(0), 7(1)]
    我们枚举 5,由于7≥5,因此移除栈顶元素 7。同样地,6≥5,再移除栈顶元素 6。此时栈为空,所以 5左侧的柱子是「哨兵」,位置为 −1。随后我们将 5 入栈。

    栈:[5(2)]
    接下来的枚举过程也大同小异。我们枚举 2,移除栈顶元素 5,得到 2 左侧的柱子是「哨兵」,位置为 −1。将 2 入栈。

    栈:[2(3)]
    我们枚举 4,5 和 9,都不会移除任何栈顶元素,得到它们左侧的柱子分别是 2,4 和 5,位置分别为 3,4 和 5。将它们入栈。

    栈:[2(3), 4(4), 5(5), 9(6)]
    我们枚举 3,依次移除栈顶元素 9,5 和 4,得到 3 左侧的柱子是 2,位置为 3。将 3入栈。

    栈:[2(3), 3(7)]
    这样以来,我们得到它们左侧的柱子编号分别为 [-1, 0, -1, -1, 3, 4, 5, 3]。用相同的方法,我们从右向左进行遍历,也可以得到它们右侧的柱子编号分别为[2, 2, 3, 8, 7, 7, 7, 8],这里我们将位置 8 看作「哨兵」。

    在得到了左右两侧的柱子之后,我们就可以计算出每根柱子对应的左右边界,并求出答案了。

  • 回到85题
    观看下图,可以看先其实逐行处理与84题处理方式一样,分别计算每个柱子的高度,然后调用84题的单调栈进行最大矩形面积的计算。

在这里插入图片描述

  • 代码
class Solution(object):
    def maximalRectangle(self, matrix):
        """
        :type matrix: List[List[str]]
        :rtype: int
        """
        if len(matrix)==0:
            return 0
        
        rows = len(matrix)
        cols = len(matrix[0])

        # 参考84题,逐层寻找最大面积的长方形
        # 使用[]模拟栈,栈里面的数字单调递增

        result =0
        for i in range(rows):
            # 使用heights记录每列柱子的高度
            heights = [0]*cols
            for j in range(cols):
                h = i
                while h >=0 and matrix[h][j]=='1':
                    h = h-1
                heights[j] = i-h
            '''
            print(i, 'cols')
            for j in range(len(heights)):
                print(heights[j])
            '''
            result = max(result, self.largestRectangleArea(heights))
        return result

    def largestRectangleArea(self, heights):
        """
        :type heights: List[int]
        :rtype: int
        """
        result = 0
        # leftMin用于记录每个柱子左侧比该柱子低的第一个柱子的位置
        leftMin = [-1]*len(heights)
        # rightMin用于记录每个柱子右侧比该柱子低的第一个柱子的位置
        rightMin = [len(heights)]*len(heights)

        # 使用单调栈,python中用[]来代替,里面装载下标
        # 先把最左边的推入栈
        stack = [0]
        for i in range(1,len(heights)):
            # 如果当前的高度比栈顶元素大,则入栈
            # 当前元素的leftMin为栈顶元素的位置
            
            if heights[i]> heights[stack[len(stack)-1]]:
                leftMin[i] = stack[len(stack)-1]
                stack.append(i)
            else:
                # 当前的元素无法直接入栈
                # 需要先将栈里面比当前元素大的元素处理完
                # 再把当前元素入栈
                while len(stack)>0 and \
                    heights[i]<=heights[stack[len(stack)-1]] :
                    stack.pop()
                if len(stack)>0:
                    leftMin[i] = stack[len(stack)-1]
                stack.append(i)
                # 如果原先栈中的所有元素都被pop出来
                # 说明没有元素比当前的元素小,则leftMin[i] = -1,初始化时已处理

        # 同样的处理逻辑处理rightMin
        stack = [len(heights)-1]
        for i in range(len(heights)-2, -1, -1):
            if heights[i]> heights[stack[len(stack)-1]]:
                rightMin[i] = stack[len(stack)-1]
                stack.append(i)
            else:
                while len(stack)>0 and \
                    heights[i]<=heights[stack[len(stack)-1]] :
                    stack.pop()
                if len(stack)>0:
                    rightMin[i] = stack[len(stack)-1]
                stack.append(i)

        # 计算每个柱子所能勾勒的最大矩形的面积
        for i in range(len(heights)):
            #print(i,leftMin[i],rightMin[i])
            result = max(result, heights[i]*(rightMin[i]-leftMin[i]-1))
        return result
  • 作业截图在这里插入图片描述

152. 乘积最大子数组

  • 思路
    使用动态规划,dpMin[i]表示包含i的最小乘积,dpMax[i]表示包含i的最大乘积,由于存在正负数,因此对于正负数而言,最大最小值的转移状态不同。
    当当前元素为正数,则转移方程为:

    dpMax = max( dpMax*nums[i], nums[i] )
    dpMin = min( dpMin*nums[i], nums[i] )
    

    当当前元素为负数,则转移方程为:

    dpMax = max( dpMin*nums[i], nums[i] )
    dpMin = min( dpMax*nums[i], nums[i] )
    
  • 代码

class Solution(object):
    def maxProduct(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        result = nums[0]
        # 使用动态规划
        # dpMin[i]表示包含i的最小乘积
        # dpMax[i]表示包含i的最大乘积
        
        dpMax = nums[0]
        dpMin = nums[0]

        for i in range(1, len(nums)):
            if nums[i]>0:
                dpMax = max( dpMax*nums[i], nums[i] )
                dpMin = min( dpMin*nums[i], nums[i] )
            elif nums[i]<0:
                dpMaxTmp = max( dpMin*nums[i], nums[i] )
                dpMin = min( dpMax*nums[i], nums[i] )
                dpMax = dpMaxTmp
            else:
                # nums[i]==0
                dpMax = 0
                dpMin = 0
            #print('i',i,'dpMax',dpMax,'dpMin' ,dpMin)
            result = max(result, dpMax)

        return result
  • 作业截图
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
GeoPandas是一个开源的Python库,旨在简化地理空间数据的处理和分析。它结合了Pandas和Shapely的能力,为Python用户提供了一个强大而灵活的工具来处理地理空间数据。以下是关于GeoPandas的详细介绍: 一、GeoPandas的基本概念 1. 定义 GeoPandas是建立在Pandas和Shapely之上的一个Python库,用于处理和分析地理空间数据。 它扩展了Pandas的DataFrame和Series数据结构,允许在其中存储和操作地理空间几何图形。 2. 核心数据结构 GeoDataFrame:GeoPandas的核心数据结构,是Pandas DataFrame的扩展。它包含一个或多个列,其中至少一列是几何列(geometry column),用于存储地理空间几何图形(如点、线、多边形等)。 GeoSeries:GeoPandas中的另一个重要数据结构,类似于Pandas的Series,但用于存储几何图形序列。 二、GeoPandas的功能特性 1. 读取和写入多种地理空间数据格式 GeoPandas支持读取和写入多种常见的地理空间数据格式,包括Shapefile、GeoJSON、PostGIS、KML等。这使得用户可以轻松地从各种数据源中加载地理空间数据,并将处理后的数据保存为所需的格式。 2. 地理空间几何图形的创建、编辑和分析 GeoPandas允许用户创建、编辑和分析地理空间几何图形,包括点、线、多边形等。它提供了丰富的空间操作函数,如缓冲区分析、交集、并集、差集等,使得用户可以方便地进行地理空间数据分析。 3. 数据可视化 GeoPandas内置了数据可视化功能,可以绘制地理空间数据的地图。用户可以使用matplotlib等库来进一步定制地图的样式和布局。 4. 空间连接和空间索引 GeoPandas支持空间连接操作,可以将两个GeoDataFrame按照空间关系(如相交、包含等)进行连接。此外,它还支持空间索引,可以提高地理空间数据查询的效率。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值