最大子序列和

题目

Alt

思路

分析问题

我们按照动态规划的思路来解题

  • 首先判断该题目是否可以使用动态规划算法来解题。我们知道,可以使用动态规划的条件有:
    • 最优化原理:问题的最优解所包含的子问题的解也是最优的
    • 无后效性:某一阶段状态一旦确定,就不受这个状态以后决策的影响,即某状态以后的过程不会影响到以前的状态
    • 有重叠子问题:即子问题之间是不独立的,一个子问题在下一阶段决策可能被多次用到

现在我们就来分析一下问题。首先,我们要知道问题的最优解是什么,很明显,我们就是要在问题:给定一个数组,找到一个具有最大和的连续数组,那么问题的最优解就是返回一个具有最大和的连续数组。那么子问题是什么?子问题的最优解又是什么呢?子问题的最优解是否是整体最优解的一部分呢?需要注意的是子问题的形式和原问题类似,只是规模变小了,下面我们逐步来分析:

  1. 让我们考虑数组范围[0,i](其中i<n),求范围内[0,i]具有最大和的连续数组,很明显,该问题就是一个子问题(因为问题的形式和原问题类似,只是规模变小了)。
  2. 那么该子问题的最优解是什么呢,问题的最优解就是返回最大和的连续数组
    3. 那么子问题的最优解是否是原问题最优解的一部分呢?问题的关键就在这。在这一题来说,就是数组范围[0,i]的最大和的连续数组是否是数组范围[0,n]内的具有最大和的连续数组的子序列呢?让我们用反证法简单证明一下:假设子问题的最优解不是原问题最优解的一部分,那么这种情况包括两种:(1)子问题的最优解和原问题的最优解有重叠部分(2)子问题的最优解和原问题的最优解没有交集
    那么对于第一种情况,如果子问题的最优解和原问题的最优解有交集,那么说明你原问题的解肯定不是最优解(比如子问题的最优解是[a,b,c,d],原问题的最优解是[b,c,d,e],他们具有交集[b,c,d],但是原问题的最优解不包含子问题的最优解,那么[b,c,d,e]肯定不是原问题的最优解,[a,b,c,d,e]才是原问题的最优解,我们要记住的是我们的最优解形式是求最大和的连续数组);对于第二种情况,

    上面的证明是错误的,我走进了一个误区:认为最优化原理就是指子问题的最优解是原问题最优解的子集,让我们来考虑一下这么一个问题:拿上例来说,数组范围[-2,1,-3]这个子问题的最优解是[1],而原问题的最优解是[4,-1,2,1],我们可以发现,对于子问题[-2,1,-3]的最优解[1]并不是原问题最优解的子集。让我们再重新解读一下最优化原理的定义:问题的最优解所包含的子问题的解也是最优的,我们该怎么解读这句话呢?我自己的理解就是:如果某个子问题包含最优解的一部分,那么该问题的最优解就是所包含原问题最优解的那一部分,还是拿数组范围[-2,1,-3]来说,此时的最优解是[1],那么当加入节点4后,子问题(此时的子问题就是指[-2,1,-3,4])的最优解就是节点[4],因为节点4是问题最优解的一部分,那么包含节点4的子问题的最优解就是[4]。

那么无后效性又是指什么呢?在该题中哪里又体现了无后效性呢?所谓无后效性是指某一阶段的状态一旦确定(这里的状态一般指的是一系列的取值),则此后过程的演变不再受此前各个状态及决策的影响,也就是说,当前的状态是以前历史的完成总结,此前的历史只能通过当前的状态去影响过程未来的演变,也就是说在推导后面阶段状态的时候,我们只关心前面阶段的状态值,不关心这个状态是怎么一步步推导出来的。,某阶段状态一旦确定,就不受之后阶段的决策影响,在本道题中,例如数组范围[-2,1,-3,4]的此时最优解为[4](也说此时的状态就为[4]),那么在加入节点-1后,数组范围[-2,1,-3,4,-1]的最优解也是[4],那么对于数组[-2,1,-3,4]的最优解并不受你之后新加入的节点的影响,通俗的来说,无论你加入多少个节点,对于我这个阶段[-2,1,-3,4]来说,我此时的最优解永远都是[4]。

最后对于子问题重叠,用一句话概括就是: 不同的决策序列,到达某个相同的阶段时,可能会产生重复的状态。 例如数组范围[-2,1,-3,4]的此时最优解为[4](也说此时的状态就为[4]),那么在加入节点-1后,数组范围[-2,1,-3,4,-1]的最优解也是[4]

实际求解问题

动态解题的一般思路就是:
(1)划分阶段
(2)确定状态和状态变量
(3)确定决策并写出状态方程
(4)寻找边界条件

具体到本道题来说:

  1. 每个阶段就是指当新加入一个节点
  2. 确定状态就是指确定在新加入该节点后此时数组的连续数组最大和的值
  3. 那么我们该做出如何的决策呢,让我们来分析一下,我们设置一个数组dp,dp[i]表示前i个元素的最大连续和,在新加入一个节点后i后,如果前面的数组[0,i-1]的最大连续和为负数,那么说明此时[0,i]的最大连续和为本身(因为一个数加上负数肯定小于它本身),如果大于0,那么最大连续和就为dp[i-1]+nums[i](我们要记住的是dp[i]保存的是前i个元素的最大连续和),所以状态转移方程应该是dp[i]=max(dp[i-1],0)+nums[i];我们又发现当前的状态只取决于前一个状态(这个就又符合贪心算法),那么我们就可以只使用一个变量来替代。
  4. 边界问题就是遍历到数组的最后一个元素
    所以相关代码如下:
class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        if (nums.size() < 1)
			return 0;
		int res = nums[0];
		int sum = nums[0];
		for (int i = 1; i < nums.size(); i++) {
			sum = max(sum + nums[i], nums[i]);
			if (sum >= res)
				res = sum;
		}
		return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值