归纳法求解最大连续子序列

(原文链接:http://www.karottc.com/blog/2014/09/07/maximum-consecutive-subsequence/)

问题

求最大连续子序列的问题描述如下:

给定一个实数序列 x1, x2, ... , xn(不必是正数),寻找一个(连续的)子序列 xi, xi+1, ... , xj,使得其数值之和在所有连续子序列数值之和中是最大的。

这个问题就是最大子序列问题,所求的的这个序列就叫做——最大子序列。下面通过数学归纳法来分析和解决这个问题,解决这个问题的最好目标是: 一个算法,能够只扫描此序列一次就得到最大子序列

归纳分析

根据上面的问题可以直接得到一般的归纳假设:

归纳假设: 已知如何找到规模小于 n 的序列的最大子序列。

下面假定一些变量:

  • 给定序列 S(n)=(x1, x2, ... , xn).
  • 序列 S(n) 的子序列为 S(n) .
  • 序列 S(n) 的最大子序列为 SM(n)=(xi, xi+1, ... , xj).
  • 序列 S(n) 的最大后缀子序列为 SE(n)=(xk, xk+1, ... , xn). 

现在开始用数学归纳法来证明:

  1. 当 n = 1 时, S(1)=x1,如果 x1<0,则 *SM(1)=NULL;否则 *SM(1)=x1 .
  2. 当 n = n-1 时,S(n-1)=(x1, x2, ... , xn-1),假设 SM(n-1)=(xi, xi+1, ... , xj).
  3. 当 n = n 时,S(n)=(x1, x2, ... , xn)=( S(n-1), xn),然后由 SM(n-1) 推导出 SM(n),共有下面3种情况:
    1. SM(n-1)=(xi, xi+1, ... , xj) = NULL,如果 xn<0,则 *SM(n)=NULL;否则 *SM(n)=xn .
    2. SM(n-1)=(xi, xi+1, ... , xj) && j = n-1,此时 SM(n-1) = SE(n-1),如果 xn > 0,SM(n)= SM(n-1) +
      xn = (xi, xi+1, ... , xj) + xn,否则 SM(n)= SM(n-1)=(xi, xi+1, ... , xj) .
    3. SM(n-1)=(xi, xi+1, ... , xj) && j < n-1,此时 SM(n-1) > SE(n-1),则可得到 SM(n)SM(n-1) 或者 SM(n)SE(n-1) +
      xn .
  4. 即上述可得证:能够求出 S(n)=(x1, x2, ... , xn) 的最大连续子序列,不过上述的证明过程中用了增强归纳假设,这个也是这个证明的关键:

    更强的归纳假设: 已知如何找到规模小于 n 的序列的最大子序列,以及作为后缀的最大子序列。

我们知道了 SM(n) 和 SE(n) 这两个序列,算法也就明确了。我们把 xn 加入到最大后缀子序列中,如果它的和大于原来的最大子序列,则得到一个新的最大子序列(同样也是一个后缀),否则,保留以前的最大子序列。但求解过程还没有结束,我们还需要寻找新的最大后缀子序列,因为不能只是简单的把 xn 加到以前的最大后缀中,有可能以 xn 结束的最大后缀的和是负数,在这种情况下,我们就需要把NULL(空集)作为最大后缀(以及把随后的
xn+1 也考虑进去)。

具体算法实现

根据上面的分析过程,下面贴上具体的C++代码:

int Maximum_Consecutive_Subsequence(int *x, int n)
{
    int global_Max = 0;   // 最大子序列的和
    int suffix_Max = 0;   // 最大后缀子序列的和,每次迭代都会更新
    int i = 0;
    for (i = 0; i < n; i++)
    {
        if (x[i] + suffix_Max > global_Max)
        {
            suffix_Max = suffix_Max + x[i];
            global_Max = suffix_Max;
        }
        else if (x[i] + suffix_Max > 0)
        {
            suffix_Max = suffix_Max + x[i];
        }
        else
        {
            suffix_Max = 0;
        }
    }
    return global_Max;
}

更详细的代码可以戳这里.

2014.09.07

时间: 2024-12-28 23:08:49

归纳法求解最大连续子序列的相关文章

求解最大连续子序列和问题

解法1:maxSubSum1(a,n)算法中用三重循环来穷举所有的连续子序列,计算它们的和,时间复杂度为T(n) = O(n^3). 1 long maxSubSum1(int a[],int n) 2 { 3 int i,j,k; 4 long maxSum = a[0],thisSum; 5 for(i = 0;i < n;i++) 6 { 7 for(j = i;j < n;j++)//两重循环穷举所有连续子序列 8 { 9 thisSum = 0; 10 for(k = i;k <

最大连续子序列和

对于给定的数组 numnum,一个长度为 ss 的连续子序列是指由 num_i,num_{i+1},num_{i+2}\ldots,num_{i+s-1}num?i??,num?i+1??,num?i+2??…,num?i+s−1?? 组成的序列.数组中的元素有可能为正数.负数或 00.你需要从数组中找出元素总和最大的一个连续子序列. 比如,对于数组 1,-3,2,6,-5,81,−3,2,6,−5,8,其最大连续子序列之和是 2+6-5+8=112+6−5+8=11. 对于一段区间内的最大连续

最大连续子序列乘积

问题描述 给定一个整数序列(可能有正数,0和负数),求它的一个最大连续子序列乘积.比如给定数组a={3, -4, -5, 6, -2},则最大连续子序列乘积为360,即3*(-4)*(-5)*6=360. 分析 求最大连续子序列乘积与最大连续子序列和问题有所不同,因为其中有正有负还有可能有0. 假设数组为a[],直接利用动归来求解,考虑到可能存在负数的情况,我们用Max[i]来表示以a[i]结尾的最大连续子序列的乘积值,用Min[i]表示以a[i]结尾的最小的连续子序列的乘积值,那么状态转移方程

sjtu oj 1250 最大连续子序列问题变形

这道题目不知道是因为做的人少还是什么原因,pass率很低,我在去图书馆的路上忽然想起这道题目和最大连续子序列其实是一个问题,但是更难,更挑剔! 1250. BestSubsequence Description LL有n个妹子,他给妹子们编号排成一排.据说今天天气大好,LL要去春游了,他决定要选定至少F个妹子一起去玩. 为了让妹子们开心,他决定选连续一段的妹子们.然后LL有个特殊的癖好,他喜欢体重比较厉害一些的妹子. 那你可以帮LL选妹子吗,使得选出来的这些妹子的平均体重最大. Input Fo

算法-最大连续子序列和

题目:给定(可能是负的)整数A1.A2.….AN,求出并确定对应的序列的最大值.如果所有的整数都是负数,那么最大连续子数列和就是0,只是求出最大值,不需要求出具体的序列,作为这个题目的变种有很多情况下给你一个确定的数列,具体求和,大同小异,共有四种解法,按照时间复杂度来解,object-c实现,解法如下: 穷举法 这个应该是这个题目最容易想到的方式,通过循环遍历出所有的序列组合,求出最大的序列的最大值,代码如下: -(NSInteger)maxSubsequenceSum:(NSArray *)

数组的最大连续子序列

今天在网上看到的这道题目: 一个有N个元素的整型数组arr,有正有负,数组中连续一个或多个元素组成一个子数组,这个数组当然有很多子数组,求子数组之和的最大值.例如:[0,-2,3,5,-1,2]应返回9,[-9,-2,-3,-5,-3]应返回-2. 开始感觉貌似也没有那么难,就直接想循环遍历+动态规划的方法写即可.O(n2)的复杂度,感觉略大,想到上次关于最大子矩阵方法适合的O(n)的方法,感觉这个问题肯定也有这样的解法.在网上搜罗了一下,果真有各种简单的方法,仔细一看,这些方法之间还有关联性,

转~最大连续子序列求和

最大连续子序列求和详解 1.        问题描述 输入一个整数序列(浮点数序列也适合本处讲的算法),求出其中连续子序列求和的最大值. 2.        算法分析 2.1.        算法一 2.1.1.       算法描述 遍历所有子序列并求和,比较得出其中的最大值. 2.1.2.       代码描述 1          public static int maxSubSumCubic(int[] array) { 2                 int maxSum = 0

最大连续子序列求和详解

最大连续子序列求和详解 1.        问题描述 输入一个整数序列(浮点数序列也适合本处讲的算法),求出其中连续子序列求和的最大值. 2.        算法分析 2.1.        算法一 2.1.1.       算法描述 遍历所有子序列并求和,比较得出其中的最大值. 2.1.2.       代码描述 1          public static int maxSubSumCubic(int[] array) { 2                 int maxSum = 0

动态规划:最大连续子序列乘积

题目描述: 给定一个浮点数序列(可能有正数.0和负数),求出一个最大的连续子序列乘积. 分析:若暴力求解,需要O(n^3)时间,太低效,故使用动态规划. 设data[i]:第i个数据,dp[i]:以第i个数结尾的连续子序列最大乘积, 若题目要求的是最大连续子序列和,则易确定状态转移方程为: dp[i]=max(data[i],dp[i-1]+data[i])(dp[i]为以第i个数结尾的连续子序列最大和) 但乘积存在负负得正的问题,即原本很小的负数成了一个负数反而变大了,(负数逆袭了), 故不能