最大子数列之和问题

给定一个数组,数组长度为n,数组中每个元素为一个整数(其中有正数,负数,零),求一和最大的子数组

这是一道老生常谈的动态规划问题,也是我大一学算法时遇到的第一道动态规划问题,当时觉得解法非常精妙,从此爱上了算法。

题目的具体解法为是dp[i][0]表示前i项数列不含最后一项(第i项)时的子数列之和的最大值,dp[i][1]表示前i项数列含最后一项的子数列之和最大值

很明显dp[i][0]=max(dp[i-1][1],dp[i-1][1]),dp[i][1]=max(dp[i-1][1]+a[i],a[i]);

但是从上面的状态转移方程可以发现,每一项只与前一项有关,所以状态转移过程中,无需记录多余的状态,只记录该状态的前一种状态即可,所以描述子状态二维数组完全可以使用 dp1 和 dp2 这两个数来代替,从而优化了空间发杂度

最终优化完成的代码如下:

#include<iostream>
#include<string>
using namespace std;
int main(){
    long long dp1,dp2,a[10000],ans;
    int n=1;
    cin>>a[0];
    while(getchar()!=‘\n‘){
        cin>>a[n++];
    }
    dp1=-99999999;ans=dp2=a[0];//为避免全为负数
    for(int i=1;i<n;i++){
        dp1=max(dp1,dp2);
        dp2=max(dp2+a[i],a[i]);
    }
    ans=max(dp1,dp2);
    cout<<ans<<endl;
    return 0;
}

第二,如果上述数列首尾相接,那样的话,其实和原来的问题依然一样,原来的问题可以看做数列在第一个元素和最后一个元素之间比存在一个断口,现在首尾相接,只要枚举一下断口的位置即可,具体代码如下:

#include<iostream>
#include<string>
using namespace std;
int main(){
    long long dp1,dp2,a[10000],ans;
    int n=1;
    cin>>a[0];
    while(getchar()!=‘\n‘){
        cin>>a[n++];
    }
    for(int j=0;j<n;j++){
        int k=j;
        dp1=-99999999;ans=dp2=a[k];
        for(int i=1;i<n;i++){
            k++;k%=n;
            dp1=max(dp1,dp2);
            dp2=max(dp2+a[k],a[k]);
        }
        ans=max(ans,max(dp1,dp2));
    }
    cout<<ans<<endl;
    return 0;
}
时间: 2024-10-13 01:22:44

最大子数列之和问题的相关文章

软工 assignment 3 —— 求最大子数列之和

题目要求 最大连续子数组和(最大子段和) 问题: 给定n个整数(可能为负数)组成的序列a[1],a[2],a[3],-,a[n],求该序列如a[i]+a[i+1]+-+a[j]的子段和的最大值.当所给的整数均为负数时定义子段和为0,依此定义,所求的最优值为: Max{0,a[i]+a[i+1]+-+a[j]},1<=i<=j<=n 例如,当(a[1],a[2],a[3],a[4],a[5],a[6])=(-2,11,-4,13,-5,-2)时,最大子段和为20. -- 引用自<百度

最大子数组之和、最大子数组之积、最长递增子序列求法

昨天做爱奇艺笔试题,最后一道编程题是求整型数组最长递增子序列,由于时间关系,没有完全写出来,今天重新来做做这一系列题. <1> 最大子数组之和 首先从最简单的最大子数组之和求取.数组里有正数.负数.零.设包含第 i 个元素的子数组的和为 Sum,则Sum的值为 Sum(i) = Sum(i-1) + arrey[i]; 显然如果arrey[i]<=0,则Sum(i)<=Sum(i-1);则必须把Sum(i)=arrey[i];同时maxSum用来保存Sum最大值.时间复杂度为o(n

《团队开发项目之三二维数组的最大子数组之和》

设计思想:按列或按行的次序依次进行计算每个以列或行的次序为基准的每种情况下的每个子矩阵的和,然后再依次进行比较每个子矩阵的和,取出最大的一个即是最大字数组之和: 源代码: //二维数组的最大子数组之和 //李敏,Apr 8th #include<iostream> #include<time.h> using namespace std; void main() { int m,n,a[100][100],k,t,c,i,j,z; int maxsum,sum[100],max=0

二维数组的最大子数组之和

一.设计思路:与求一维数组的最大子数组类似,将二维数组转化为一维数组来计算,也是通过遍历的方式将一个子矩阵与上几个子矩阵相加如果小于0则舍去这个子矩阵,按此方法计算从这个子矩阵以后的矩阵,求得遍历中最大值,即为最大子数组之和. 二.代码: package soft_third_test; public class test { static int maxSum(int p[][],int startLine,int endLine,int n){ int ans=p[endLine][1]-p

软件工程结对开发之求二维数组中连续最大子数组之和2

一.题目要求 题目:返回一个二维整数数组中最大子数组的和. 要求: 输入一个二维整形数组,数组里有正数也有负数. 二维数组首尾相接,象个一条首尾相接带子一样. 数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和. 求所有子数组的和的最大值.要求时间复杂度为O(n). 二.设计思路 先调用以前求二维最大连续子数组之和的maxSubArray函数求一个首尾不相邻的二维最大连续子数组之和,接着用将第k列各元素左移一列可以再求一个最大连续子数组之和 ,循环m次(因为原二维数组有m列)求得每个

5、软件工程结对开发之求一维数组中连续最大子数组之和

一.题目:返回一个二维整数数组中最大子数组的和.二.要求:输入一个二维整形数组,数组里有正数也有负数.二维数组首尾相接,象个一条首尾相接带子一样.数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和.求所有子数组的和的最大值.要求时间复杂度为O(n). 三.设计思想 这个实验是在前几次实验的基础上,利用动态数组,为了满足首尾相连,所以在计算一次之后,要把该数放在数组的最后边,这样循环遍历最后求出最大子数组的和. 四.源代码 1 #include <iostream.h> 2 int

有负数项的数列之和

问题:编写函数计算数列前n项之和,数列为1-2+3-4+5-6+7-8+....... 这个问题简单,编写一个计算数列之和的函数太容易了. 人们通常用计算解决问题,也就是编写程序解决问题.然而,编写程序解决问题,是多解的,即不同的程序可以计算出相同的结果. 解决这个问题,编写了3个不同的函数. 函数sum1(),遇到正数项则相加,遇到负数项则相减,使用逻辑判定来决定是做相加还是相减,即对于奇数项做加法计算,对于偶数项做减法计算. 函数sum2(),也是用一般累加求和的计算,对于每一项进行求和计算

环形数组求最大子数组之和

环形数组求最大子数组之和: 实验要求: 随机产生一个整形数组,假设首尾相连为环形,求其相连的字数组的和,并输出子数组的元素. 设计思路: 因为是环形,所以要考虑自设的头尾的情况,在此分为两大类考虑,一种为数组中存在正数情况,一种为全部为负数的情况: 在存在正数的情况中又可分为三种情况,一种为全部为正数的情况,一种为自设的头元素为正数,最后一种为自设的头元素为负数.根据这几种情况分类进行实现. 在实现过程中,对数组元素从头到尾进行遍历,如果遇到正数即用和相加,直到相邻的下一个为负数,即存放目前该最

课堂练习求环整数组中最大子数组之和

设计思路:之前还有一个课堂练习,是用户输入一个整数组,求其中最大子数组之和,我借鉴的其他同学的代码,仅在此基础上修改的.运用try,catch使得用户不必在输入数组之前输入数组的长度,但是需要一个除整数以外的数来结尾.一共使用了3个循环,运用一个循环得出每个数组中最大子数组之和的最大值,一个是用来计算最大子数组之和,最后一个用来实现数组的前移.第一个循环中包着另外两个循环.总的来说,是在之前课堂练习的基础上增加了将一个数组中的每个数做一次最前面的数,从中求出最大值. 程序代码: 1 import