【题目】

给定k个整数的序列{N1,N2,...,Nk },其任意连续子序列可表示为{ Ni, Ni+1, ..., Nj },其中 1 <= i <= j <= k。最大连续子序列是所有连续子序中元素和最大的一个,例如给定序列{ -2, 11, -4, 13, -5, -2 },其最大连续子序列为{11,-4,13},最大连续子序列和即为20。

【注】:为方便起见,如果所有整数均为负数,则最大子序列和为0。

解决这样一个问题是一个很有趣的过程,我们可以尝试着从复杂度比较高的算法一步一步地推出复杂度较低的算法。

【算法1】

时间复杂度:O(N^3)

int MaxSubSequence(const int A[], int N){int ThisSum,MaxSum,i,j,k;MaxSum = 0;for(i=0;i<N;i++){for(j=i;j<N;j++){ThisSum = 0;for(k=i;k<=j;k++){ThisSum += A[k];}if(ThisSum > MaxSum)MaxSum = ThisSum;}}return MaxSum;
}

对于此种算法,其主要方法是穷举法,即求出该序列所有子序列的序列和,然后取最大值即可。

【算法2】

时间复杂度:O(N^2)

int MaxSubSequence(const int A[], int N){int ThisSum,MaxSum,i,j;MaxSum = 0;for(i=0;i<N;i++){ThisSum = 0;for(j=i;j<N;j++){ThisSum += A[j];if(ThisSum > MaxSum)MaxSum = ThisSum;}}return MaxSum;
}

【分析】

对于这种方法,归根究底还是属于穷举法,其间接地求出了所有的连续子序列的和,然后取最大值即可。

那么,这里,我们需要对比一下前面两种算法,为什么同样都是穷举法,但算法一的时间复杂度远高于算法二的时间复杂度?

算法二相较于算法一,其优化主要体现在减少了很多重复的操作。

对于A-B-C-D这样一个序列,

算法一在计算连续子序列和的时候,其过程为:

A-B、A-C、A-D、B-C、B-D、C-D

而对于算法二,其过程为:

A-B、A-C、A-D、B-C、B-D、C-D

其过程貌似是一样的,但是算法一的复杂就在于没有充分利用前面已经求出的子序列和的值。

举个例子,算法一在求A-D连续子序列和的值时,其过程为A-D = A-B + B-C + C-D;

而对于算法二,A-D连续子序列和的求值过程为A-D = A-C+C-D;

这样,算法二充分利用了前面的计算值,这样就大大减少了计算子序列和的步骤。

【算法3:递归法(分治法)】

时间复杂度:O(NlogN)

易知,对于一数字序列,其最大连续子序列和对应的子序列可能出现在三个地方。或是整个出现在输入数据的前半部(左),或是整个出现在输入数据的后半部(右),或是跨越输入数据的中部从而占据左右两半部分。前两种情况可以通过递归求解,第三种情况可以通过求出前半部分的最大和(包含前半部分的最后一个元素)以及后半部分的最大和(包含后半部分的第一个元素)而得到,然后将这两个和加在一起即可。

int MaxSubSequence(const int A[],int N)
{return MaxSubSum(A,0,N-1);
}static int MaxSubSum(const int A[], int Left, int Right)
{int MaxLeftSum,MaxRightSum;int MaxLeftBorderSum,MaxRightBorderSum;int LeftBorderSum,RightBorderSum;int Center,i;if(Left == Right){if(A[Left] > 0)return A[Left];elsereturn 0;}Center = (Left + Right)/2;MaxLeftSum = MaxSubSequence(A,Left,Center);MaxRightSum = MaxSubSequence(A,Center+1,Right);MaxLeftBorderSum = 0;LeftBorderSum = 0;for(i = Center;i >= Left;i--){LeftBorderSum += A[i];if(LeftBorderSum > MaxLeftBorderSum)MaxLeftBorderSum = LeftBorderSum;}MaxRightBorderSum = 0;RightBorderSum = 0;for(i = Center+1;i <= Right;i++){RightBorderSum += A[i];if(RightBorderSum > MaxRightBorderSum)MaxRightBorderSum = RightBorderSum;}  return Max(MaxLeftSum,MaxRightSum,MaxLeftBorderSum + MaxRightBorderSum);
} int Max(int a, int b, int c)
{if(a>b&&a>c)return a;else if(b>a&&b>c)return b;elsereturn c;
}

现在对上面的代码进行相关说明:

Center变量所确定的值将处理序列分割为两部分,一部分为Center前半部,一部分为Center+1后半部。

在上文,我们提到,最大连续子序列的出现位置有三种情况。

对于前两种情况,我们根据递归特性,可以得到:

MaxLeftSum = MaxSubSequence(A,Left,Center);
  MaxRightSum = MaxSubSequence(A,Center+1,Right);

而对于第三种情况,我们需要先求出前半部包含最后一个元素的最大子序列:

MaxLeftBorderSum = 0;
  LeftBorderSum = 0;
  for(i = Center;i >= Left;i--)
  {
    LeftBorderSum += A[i];
    if(LeftBorderSum > MaxLeftBorderSum)
      MaxLeftBorderSum = LeftBorderSum;
  }

然后,再求出后半部包含第一个元素的最大子序列:

MaxRightBorderSum = 0;
  RightBorderSum = 0;
  for(i = Center+1;i <= Right;i++)
  {
    RightBorderSum += A[i];
    if(RightBorderSum > MaxRightBorderSum)
      MaxRightBorderSum = RightBorderSum;
  }

最后,我们只需比较这三种情况所求出的最大连续子序列和,取最大的一个,即可得到需要求解的答案。

return Max(MaxLeftSum,MaxRightSum,MaxLeftBorderSum + MaxRightBorderSum);

我们在介绍这个算法的开始,就已经提到了其时间复杂度,现在做一个推导:

令T(N)是求解大小为N的最大连续子序列和问题所花费的时间。

当N==1时,T(1) = 1;

当N>1时,T(N) = T(N/2) + O(N);

有数学推导公式,我们可以得到:

      T(N) = NlogN + N =O(NlogN)。

【 算法四:动态规划法】

时间复杂度:O(N)

终于到了动态规划的部分了,这么一步一步走来,感受到了算法的无穷魅力。那么如何用动态规划来处理这个问题?

首先,我们重温将一个问题用动态规划方法处理的准则:

“最优子结构”、“子问题重叠”、“边界”和“子问题独立”。

在本问题中,我们可以将子序列与其子子序列进行问题分割。

最后得到的状态转移方程为:

       MaxSum[i] = Max{ MaxSum[i-1] + A[i], A[i]};

在这里,我们不必设置数组MaxSum[]。

代码实现:

int MaxSubSequence(const int A[], int N)
{int ThisSum,MaxSum,j;ThisSum = MaxSum =0;for(j = 0;j < N;j++){ThisSum += A[j];if(ThisSum > MaxSum)MaxSum = ThisSum;else if(ThisSum < 0)ThisSum = 0; }return MaxSum;
}

在本代码实现中,ThisSum持续更新,同时整个过程,只对数据进行了一次扫描,一旦A[i]被读入处理,它就不再需要被记忆。

小结:

整个过程是一个思想的选择问题,从最初的穷举法,到分治法,再到动态规划法。算法设计思想的灵活选择是处理一个实际问题的关键。

最大连续子序列和:动态规划经典题目相关推荐

  1. 动态规划经典题目——最大子矩阵和

    一.题目 题目描述:现给出一个N*N矩阵,要求求出拥有最大和的子矩阵的和.例子如下图所示: 它的最大子矩阵的和为15: 二.解题思路 此题的解法与动态规划经典题目--最大连续子序列之和题目思想一样,只 ...

  2. 动态规划经典题目整理

    动态规划经典题目整理 背包问题 最长公共子串问题 连续数组最大和问题 持续增加中.... 背包问题 复杂度 O(nW)O(nW)O(nW) nnn为物品种类,WWW是背包的重量 目的:使得背包中的物品 ...

  3. 动态规划经典题目-数据压缩之图像压缩

    文章目录 一.题目描述 二.解题思路 1. 定义状态 2. 定义状态转移方程 3. 初始化 4. 计算方式 三.代码实现 四.执行结果 五.思考 一.题目描述 ​ 计算机中的图像由一系列像点构成,每个 ...

  4. 动态规划经典题目_动态规划经典题目:鸡蛋掉落(附视频讲解)

    题目: 思路: 先放上视频讲解 动态规划经典题目:鸡蛋掉落https://www.zhihu.com/video/1225199247848513536 纠正:视频里的状态转移方程漏写了一个+1,意思 ...

  5. 动态规划经典题目-最小权三角剖分

    文章目录 一.题目描述 二.解题思路 1. 定义状态 2. 定义状态转移方程 3. 初始化 4. 计算方式 三.代码实现 四.执行结果 五.思考 一.题目描述 设A是顶点为0,1,-,n-1的n凸多边 ...

  6. 动态规划经典题目——最大连续子序列之和

    一.题目 给定K个整数的序列{ N1, N2, -, NK },其任意连续子序列可表示为{ Ni, Ni+1, -, Nj },其中 1 <= i <= j <= K.最大连续子序列 ...

  7. 动态规划经典题目:最大连续子序列和、最大不连续子序列和

    1.最大连续子序列和:  记数组为nums 思路: 记录dp[i]为i位置结尾的最大连续子序列和 则有dp[i]=dp[i-1]>0?(dp[i-1]+nums[i]):nums[i]; 然后求 ...

  8. 最大连续子序列和-动态规划

    题目描述: 给定K个整数的序列{ N1, N2, -, NK },其任意连续子序列可表示为{ Ni, Ni+1, -, Nj },其中 1 <= i <= j <= K.最大连续子序 ...

  9. 动态规划经典题目汇总

    http://www.cppblog.com/doer-xee/archive/2009/12/05/102629.html 转载之前先Orz一下: [s:19] Robberies http://a ...

最新文章

  1. 程序员离职后躲老家山洞 2 年,敲出 45 万行代码...
  2. java中去掉Sprit(arg0)中正则表达式干扰
  3. Yet Another Meme Problem(打表找规律)
  4. 【渝粤题库】广东开放大学 基础写作 形成性考核
  5. 在vscode上编写jsp_使用vscode高效编写博客园博客
  6. Linux下如何定位Java进程CPU利用率过高原因
  7. java中包容易出现的错误及权限问题
  8. 电脑开机出现奇怪字符_电脑开机出现Reboot and select proper boot device几种解决措施...
  9. sphereface result
  10. 【转】angularjs指令中的compile与link函数详解
  11. 基于Android的百度地图显示
  12. R语言使用aov函数进行单因素方差分析(One-way ANOVA)、使用multcomp包的glht函数检验组均值之间所有成对对比差异、使用plot函数可视化Tukey HSD两两均值比较图
  13. 一元二次方程的c语言代码,一元二次方程求解程序完整代码
  14. 人工智能专业应不应该读博士?
  15. python的数据处理
  16. 蓝色主机 bluehost主机 启用CloudFlare的cdn加速服务
  17. 如何在CSDN中发布文章
  18. python库:Pandas学习笔记
  19. 根据排队论阐述路由器和高速公路的拥堵以及拥堵缓解问题
  20. Hadoop精华问答 | 基于Hadoop的数据中心有什么好处?

热门文章

  1. 标准BP算法用Python编程实现
  2. (IOS可自动播放)使用bxslider做了一个切换图片跟随播放MP3的功能
  3. Vue框架设置响应式布局
  4. C语言结构体函数指针
  5. WOJ:Pinhole Imaging
  6. 那是计算机房吗不它不是 英语,人教版四年级下册英语unit1教材B部分课文翻译...
  7. 【报告分享】2020年全国二手车市场深度分析-中国汽车流通协会(附下载)
  8. IIT_CS480_Assignments_Week10_Participation
  9. vs中opencv如何实现掩膜_OpenCV之旋转和掩膜 | 学步园
  10. 通过 Browserify 在浏览器中使用 NodeJS 模块