每天刷两道题——第四天

本文介绍了如何使用动态规划算法解决最大子数组和问题,并扩展到求解任意子数组和的绝对值最大问题。通过定义子问题、状态转移方程和初始化过程,展示了如何计算给定数组中特定类型的子数组和的最大值。
摘要由CSDN通过智能技术生成

1.1最大子数组和

给一个整数数组 nums ,找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

动态规划

   动态规划也称为动态优化,把复杂问题分解为子问题,通过求解子问题,组合子问题的解从而得到整个问题的解。参考文章

动态规划适用于:
1.一个复杂问题的最优解由数个小问题的最优解构成,可以通过寻找子问题的最优解来得到复杂问题的最优解,这个特性又称为最优子结构(optimal substructure);例如:最短路径
2.子问题在复杂问题内重复出现,使得子问题的解可以被存储起来重复利用,这个特性又称为重叠子问题(overlapping subproblem)。例如:斐波拉契数列。

动态规划的无后效性

为了保证计算子问题能够按照顺序、不重复地进行,动态规划要求已经求解的子问题不受后续阶段的影响。这个条件也被叫做「无后效性」。换言之,动态规划对状态空间的遍历构成一张有向无环图,遍历就是该有向无环图的一个拓扑序。有向无环图中的节点对应问题中的「状态」,图中的边则对应状态之间的「转移」,转移的选取就是动态规划中的「决策」。

动态规划题解的步骤:状态定义、状态转移方程、初始化、输出、是否可以空间优化。

1.定义子问题:

子问题 1:以 −2 结尾的连续子数组的最大和是多少;
子问题 2:以 1 结尾的连续子数组的最大和是多少;
子问题 3:以 −3 结尾的连续子数组的最大和是多少;
子问题 4:以 4结尾的连续子数组的最大和是多少;
子问题 5:以 −1 结尾的连续子数组的最大和是多少;
子问题 6:以 2 结尾的连续子数组的最大和是多少;
子问题 7:以 1结尾的连续子数组的最大和是多少;
子问题 8:以 −5结尾的连续子数组的最大和是多少;
子问题 9:以 4 结尾的连续子数组的最大和是多少。

2.定义状态

d p [ i ] dp[i] dp[i]:表示以 n u m s [ i ] nums[i] nums[i]结尾 的 连续 子数组的最大和。

3.状态转移方程(子问题之间的联系)

n u m s [ i ] nums[i] nums[i]结尾的连续子数组与以 n u m s [ i − 1 ] nums[i - 1] nums[i1] 结尾的连续子数组只相差一个元素 n u m s [ i ] nums[i] nums[i]

假设数组 n u m s nums nums 的值全都严格大于 0,那么一定有 d p [ i ] = d p [ i − 1 ] + n u m s [ i ] dp[i] = dp[i - 1] + nums[i] dp[i]=dp[i1]+nums[i]

可是 d p [ i − 1 ] dp[i - 1] dp[i1]有可能是负数,于是分类讨论:
  如果 d p [ i − 1 ] > 0 dp[i - 1] > 0 dp[i1]>0,那么可以把 n u m s [ i ] nums[i] nums[i] 直接接在 d p [ i − 1 ] dp[i - 1] dp[i1] 表示的那个数组的后面,得到和更大的连续子数组;
  如果 d p [ i − 1 ] < = 0 dp[i - 1] <= 0 dp[i1]<=0,那么 n u m s [ i ] nums[i] nums[i] 加上前面的数 d p [ i − 1 ] dp[i - 1] dp[i1] 以后值不会变大。于是 d p [ i ] dp[i] dp[i] 「另起炉灶」,此时单独的一个 n u m s [ i ] nums[i] nums[i] 的值,就是 d p [ i ] dp[i] dp[i]

以上两种情况的最大值就是 d p [ i ] dp[i] dp[i]的值,写出如下状态转移方程:
d p [ i ] = { d p [ i − 1 ] + n u m s [ i ] if  d p [ i − 1 ] > 0 n u m s [ i ] if  d p [ i − 1 ] < = 0 dp[i]= \begin{cases} dp[i-1]+nums[i] &\text{if } dp[i-1]>0\\ nums[i] &\text{if } dp[i-1]<=0 \end{cases} dp[i]={dp[i1]+nums[i]nums[i]if dp[i1]>0if dp[i1]<=0

4.初始化

d p [ 0 ] dp[0] dp[0] 根据定义,只有 1 个数,一定以 n u m s [ 0 ] nums[0] nums[0]结尾,因此 d p [ 0 ] = n u m s [ 0 ] dp[0] = nums[0] dp[0]=nums[0]

5.输出

这个问题的输出是把所有的 d p [ 0 ] 、 d p [ 1 ] 、 … … 、 d p [ n − 1 ] dp[0]、dp[1]、……、dp[n - 1] dp[0]dp[1]……dp[n1]都看一遍,取最大值。

6.是否可以优化空间

一般的问题只要时间复杂度最优就可以。
空间复杂度 o n l i n e j u d g e online judge onlinejudge并不在意,只要使用的空间不太离谱,不要一上来就 i n t [ ] d p = n e w i n t [ I n t e g e r . M A X V A L U E ] int[] dp = new int[Integer.MAX_VALUE] int[]dp=newint[Integer.MAXVALUE]就好。

7.代码

class question1:
	    def maxSubArray(self,nums):
        size=len(nums)
        pre=0  #初始状态
        res=nums[0]  #存储每个状态中的最大值
        for i in range(size):
            pre=max(nums[i],pre+nums[i]) #计算以nums[i]结尾的最大值
            res=max(res,pre)
        return res
q = question1()
print(q.maxSubArray([-2,1,-3,4,-1,2,1,-5,4]))       

1.2任意子数组和的绝对值的最大值

数组 [ n 1 , n 2 , n 3 , . . . , n r − 1 , n r ] 的和的绝对值为 a b s ( n 1 + n 2 + n 3 + . . . + n r − 1 + n r ) 数组[n_1,n_2,n_3,...,n_{r-1},n_r]的 和的绝对值 为abs(n_1+n_2+n_3+...+n_{r-1}+n_r) 数组[n1,n2,n3,...,nr1,nr]的和的绝对值为abs(n1+n2+n3+...+nr1+nr)

其中abs()为取绝对值,定义如下:
1.如果 x 是负整数,那么 a b s ( x ) = − x abs(x) = -x abs(x)=x
2.如果 x 是非负整数,那么 a b s ( x ) = x abs(x) = x abs(x)=x

请你找出 nums 中 和的绝对值 最大的任意子数组(可能为空),并返回该最大值 。子数组是数组中的一个连续非空序列。

输入:nums = [2,-5,1,-4,3,-2]
输出:8
解释:子数组 [-5,1,-4] 和的绝对值最大,为 abs(-5+1-4) = abs(-8) = 8 。

nums 中 和的绝对值 最大的任意子数组可能是这个数组的子数组最大和的绝对值,也可能是这个数组的子数组最小和的绝对值,按照1.1的动态规划思路,求取数组的子数组最大和和子数组最小和。

class question1:
    def maxAbsoluteSum(self,nums):
        preMax,preMin=0,0
        resMax,resMin=nums[0],nums[0]

        for i in range(len(nums)):
            preMax=max(nums[i],nums[i]+preMax)
            resMax=max(resMax,preMax)

            preMin = min(nums[i], nums[i] + preMin)
            resMin = min(preMin, resMin)

        return max(abs(resMax),abs(-resMin))

q = question1()
print(q.maxAbsoluteSum([2,-5,1,-4,3,-2]))
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值