力扣连续数列问题----今天又是动态规划的一天

面试题 16.17. 连续数列

给定一个整数数组,找出总和最大的连续数列,并返回总和。

示例:

输入: [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

题解:

对于本题,我们可以先细细考虑一下题目,题目上说让我们找出总和最大的连续数列,再返回其总和。
既然如此,如果设i为0~numSize中的某个数(i可以从0一直增加到numsize),我们将数组以i下标结尾的最大连续子序列都求出来,最后再进行一次max比较即可。因为最大连续子序列一定是以0
~numsize的一个下标作为结尾元素的。

且对于数列中的任意一个数,其有两种可能:
1.在形成子列的过程中与前面连一块。
2.不与前面相连。

即:

每一个数据都有两个选择,与前面相连或者自己白手起家。

所以可知以i为结束元素下标是有两种可能性的,我们先进行一次max把大的选出来即满足了我们的“以i结尾的 最大 连续子序列”

所以我们可以列出状态转移方程:
dp[i]表示以i结尾的最大连续子序列
dp[i] = max(dp[i - 1] + nums[i],nums[i]);

并且我们不需要将所有的以i结尾的最大连续子列都求出来,求出来两个我们就比较一下舍弃一个即可。

附:
代码中:dp[i]=Max(dp[i-1]+nums[i],nums[i]);//此即为判断一下哪种情况下以i作为结束元素下标最“好”。

代码中:max=Max(dp[i],max);//自然此时以i为结束元素下标并不一定是最好的,可能不以i作为结束下标更好,于是来了一个比较。
代码

int Max(int x,int y)
{
    return x>y?x:y;
}
int maxSubArray(int* nums, int numsSize){
    if(numsSize==0)
    return 0;
    int dp[numsSize];
    dp[0]=nums[0];
    int max = dp[0];
    for(int i=1;i<numsSize;i++)
    {
        dp[i]=Max(dp[i-1]+nums[i],nums[i]);//此即为判断一下哪种情况下以i作为结束元素下标最“好”
        max=Max(dp[i],max);//自然此时以i为结束元素下标并不一定是最好的,
        					//可能不以i作为结束下标更好,于是来了一个比较
    }
    return max;
}

当然或许会有另一种设法,即我们设dp[i]为有i个数时其最大子序列的大小。
这样类似的我们可以得到下列代码:

int max(int a,int b,int c)
{
    int temp = a>b?a:b;
    return temp>c?temp:c;
}
int maxSubArray(int* nums, int numsSize){
    if(numsSize==0)
        return 0;
    int dp[numsSize+1];
    dp[1]=nums[0];
    for(int i=2;i<=numsSize;i++)
    {
        dp[i]=max(dp[i-1]+nums[i-1],nums[i-1],dp[i-1]);//会出现不连续的情况
    }
    return dp[numsSize];
}

但我们会发现不对的地方,即由于我们的dp[i]只是代表有i个数时其最大子序列的大小,并不是一定包含第i个数,因此代码中的dp[i-1]+nums[i-1]此时就不一定是连续的了。所以不可这样写。而我们先前那个之所以可以是因为我们定义了以下标i为结尾了,所以一定连续。

当然啦,老规矩,能动态规划便可以使用滚动数组来进行优化~
代码:

int Max(int x,int y)
{
    return x>y?x:y;
}
int maxSubArray(int* nums, int numsSize){
    if(numsSize==0)
    return 0;
    int first,second;
    first=nums[0];
    int max = first;
    for(int i=1;i<numsSize;i++)
    {
        second=Max(first+nums[i],nums[i]);
        max=Max(second,max);
        first=second;
    }
    return max;
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

向光.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值