当前位置: 首页 > news >正文

[leetcode] 动态规划 - 最大子数组和


最大子数组和系列题目的核心算法是Kadane算法:定义状态f[i]表示以a[i]结尾的最大子数组和,不和i左边拼起来就是f[i] = a[i],和i左边拼起来就是f[i] = f[i-1] + a[i],取最大值就得到了状态转移方程f[i] = max(f[i-1], 0) + a[i],答案为max(f)

子数组非空

53. 最大子数组和 [Medium]
1186. 删除一次得到子数组最大和 [Medium]
918. 环形子数组的最大和 [Medium]

# 53. 最大子数组和
class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        n=len(nums)
        # 子数组非空
        f=[nums[0]]+[0]*(n-1)
        # 子数组可以为空:
        # f=[0]*n
        for i in range(1,n):
            f[i]=max(f[i-1],0)+nums[i]
        return max(f)

最大子数组和系列主要有两类,子数组可以为空和子数组非空。如果子数组非空,那么f数组初始化为f=[nums[0]]+[0]*(n-1),如果优化空间,不定义数组,那么ans必须初始化为-inf

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        # 子数组非空
        ans, f = -inf, 0
        # 子数组可以为空
        # ans = f = 0
        for x in nums:
            f = max(f, 0) + x
            ans = max(ans, f)
        return ans
# 1186. 删除一次得到子数组最大和
class Solution:
    def maximumSum(self, arr: List[int]) -> int:
        f=[[-inf,-inf]]+[[0,0] for _ in arr]
        
        for i,x in enumerate(arr):
            f[i+1][0]=max(f[i][0],0)+x
            f[i+1][1]=max(f[i][1]+x,f[i][0])
        return max(max(r) for r in f)

这题涉及到枚举每个元素时删或不删,有点类似状态机DP。同样地,子数组非空,所以f初始状态为-inf

# 918. 环形子数组的最大和
class Solution:
    def maxSubarraySumCircular(self, nums: List[int]) -> int:
        
        fmax,ansMax,fmin,ansMin=0,-inf,0,0
        
        for x in nums:
            fmax=max(fmax,0)+x
            ansMax=max(ansMax,fmax)
            fmin=min(fmin,0)+x
            ansMin=min(ansMin,fmin)
        # ansMax<0表示nums中元素全负,返回负值最小的
        return max(ansMax,sum(nums)-ansMin) if ansMax>0 else ansMax

这题要同时求求最大子数组和和最小子数组和。

子数组可以为空

2606. 找到最大开销的子字符串 [Medium]
1749. 任意子数组和的绝对值的最大值 [Medium]
1191. K 次串联后最大子数组之和 [Medium]
2321. 拼接数组的最大分数 [Hard]

# 2606. 找到最大开销的子字符串
class Solution:
    def maximumCostSubstring(self, s: str, chars: str, vals: List[int]) -> int:
        value_dict = dict(zip(chars, vals))
		# 子数组可以为空
        f=[0]*(len(s)+1)
        for i,c in enumerate(s):
            f[i+1] = max(f[i],0) + value_dict.get(c, ord(c)-ord('a')+1)

		# 优化空间
		# ans = f = 0
        # for c in enumerate(s):
        #     f = max(f,0) + value_dict.get(c, ord(c)-ord('a')+1)	
        #     ans = max(ans, f)	
        # return ans
        return max(f)

这道题就是子数组可以为空,所以f数组初始化为 f = [0]*(len(s)+1)

# 1749. 任意子数组和的绝对值的最大值
class Solution:
    def maxAbsoluteSum(self, nums: List[int]) -> int:
        ans = fmax = fmin = 0

        for x in nums:
            fmax = max(fmax, 0) + x
            fmin = min(fmin, 0) + x
            ans = max(ans, fmax, -fmin)

        return ans

这题是求绝对值的最大值,所以要算最大子数组和和最小子数组和,最后取两者的最大值。

# 1191. K 次串联后最大子数组之和
MOD=10**9+7
class Solution:
    # kadane算法, 用于求解最大子数组和
    def kadane(self,nums:List[int])->int:
        ans=f=0
        for x in nums:
            f=max(f,0)+x
            ans=max(ans,f)
        return ans
        
    def kConcatenationMaxSum(self, arr: List[int], k: int) -> int:
        if k==1:
            return self.kadane(arr)
            
        twoMax=self.kadane(arr*2)
        if sum(arr)<0:
            return twoMax%MOD
        else:
            return (twoMax+sum(arr)*(k-2))%MOD

子数组可以为空,ans初始化为0

# 2321. 拼接数组的最大分数
class Solution:
    def kadane(self,nums1,nums2):
        ans=f=0
        
        for x,y in zip(nums1,nums2):
            f=max(f,0)+y-x
            ans=max(ans,f)
        return sum(nums1)+ans
    
    def maximumsSplicedArray(self, nums1: List[int], nums2: List[int]) -> int:
         return max(self.kadane(nums1,nums2),self.kadane(nums2,nums1))

拓展 - 乘积最大子数组

152. 乘积最大子数组 [Medium]
2708. 一个小组的最大实力值 [Medium]

# 152. 乘积最大子数组
class Solution:
    def maxProduct(self, nums: List[int]) -> int:
        ans=-inf
        fmax=fmin=1
        for x in nums:
            
            #fmin=min(fmax*x,fmin*x,x)
            #fmax和fmin必须写在同一表达式同时更新,分开先后更新的话,后更新的就会使用新的值,导致错误
            fmax,fmin=max(fmax*x,fmin*x,x),min(fmax*x,fmin*x,x)
            ans=max(ans,fmax)
        return ans

乘积也是需要求最大乘积子数组和最小乘积子数组,因为负负得正,最小乘积子数组也可能变成最大乘积子数组。

# 2708. 一个小组的最大实力值
class Solution:
    def maxStrength(self, nums: List[int]) -> int:
    	# 子数组非空
        mx=mn=nums[0]
        
        for x in nums[1:]:
            mx,mn=max(mx,mx*x,mn*x,x),min(mn,mx*x,mn*x,x)
        return mx


以上整理自leetcode灵神题单:动态规划之 1.3 最大子数组和

相关文章:

  • Spring Boot 实战:轻松实现文件上传与下载功能
  • 深入理解 Vue3 中 ref 与 reactive 的区别及应用
  • matlab 柴油机冷却系统仿真计算
  • Cursor笔记
  • vue3.x 的 toRef详细解读
  • win10 系统 自定义Ollama安装路径 及模型下载位置
  • 如何优化API接口的性能?
  • 动态表格案例
  • Spring Boot + ShardingSphere 踩坑记
  • 从零开始学Python爬虫:(二)使用基本库urllib(下)
  • C语言中printf()函数,格式输出符
  • 【vue3】响应式的几个重要API
  • 一学就废|Python基础碎片,Pathlib模块
  • 一.AI大模型开发-初识机器学习
  • vue3.x 的provide 与 inject详细解读
  • 用C++实现点到三角形最小距离的计算
  • 基于springboot的超时代停车场管理平台(源码+文档)
  • LabVIEW与USB设备开发
  • 关于post和get的请求参数问题
  • [JVM篇]虚拟机性能监控、故障处理工具
  • 专访|200余起诉讼,特朗普上台100天,美国已进入宪政危机
  • 中国人保一季度业绩“分化”:财险净利增超92%,寿险增收不增利
  • 外交部:美方应在平等、尊重和互惠的基础上同中方开展对话
  • 比熬夜更伤肝的事,你可能每天都在做
  • 三位成功女性,如何应对失败
  • 外交部回应涉长江和记出售巴拿马运河港口交易:望有关各方审慎行事,充分沟通