题目名:最大子段和
- 实践题目
给定n个整数(可能为负数)组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的子段和的最大值。当所给的整数均为负数时,定义子段和为0。
要求算法的时间复杂度为O(n)。
输入格式:
输入有两行:
第一行是n值(1<=n<=10000);
第二行是n个整数。
输出格式:
输出最大子段和。
输入样例:
在这里给出一组输入。例如:
6
-2 11 -4 13 -5 -2
输出样例:
在这里给出相应的输出。例如:
20
- 问题描述:
给出一串数字,找出其中连续的最大的子段和
- 算法描述:
本章涉及动态规划,加上老师上课时候给的提示,把子段拆分成前半部分和最后一个数字S[i],如果S[i]前面的子段和是负数,那么就取S[i]为当前最大的子段和。用这样的方法就可以设计出我们想要的递归方程
Max = maxtmp + S[i] when maxtmp >= 0
Max = S[i] when maxtmp < 0
代码实现:
#include<iostream>
using namespace std;
int fun(int *a,int n){
int tmpsum = 0;
int maxsum = 0;
for(int i = 0; i < n; i++){
tmpsum = (tmpsum + a[i]) > a[i] ? (tmpsum + a[i]) : a[i];
if (tmpsum > maxsum){
maxsum = tmpsum;
}
}
return maxsum;
}
int main(){
int n;
cin>>n;
int a[n];
for(int i = 0; i < n; i++){
cin >> a[i];
}
cout<<fun(a,n);
return 0;
}
- 复杂度分析
时间复杂度:因为只用了一个for循环,所以时间复杂度是O(n);
空间复杂度:没有额外建立其他的数组,所以空间复杂度是O(1)。
- 心得体会:
动态规划一个很容易把人绕晕的东西,如果思路清晰,能够写出子问题的递归方程,那么可以就可以将问题的解分解成子问题的解。如何能够快速地在拿到一个题目后获得清楚的解题思路,我想应该只有一个办法,多做题。
另外附上我的算法好伙伴韦明杰给我分享的一篇博客,是有关于动态规划的,感谢他的分享:
https://blog.csdn.net/basycia/article/details/52072943
摘抄部分内容如下:
动态规划所处理的问题是一个多阶段决策问题,一般由初始状态开始,通过对中间阶段决策的选择,达到结束状态。这些决策形成了一个决策序列,同时确定了完成整个过程的一条活动路线(通常是求最优的活动路线)。如图所示。动态规划的设计都有着一定的模式,一般要经历以下几个步骤。
┌───┐┌───┐┌───┐
初始状态→│决策1│→│决策2│→…→│决策n│→结束状态
└───┘└───┘└───┘
(1)划分阶段:按照问题的时间或空间特征,把问题分为若干个阶段。在划分阶段时,注意划分后的阶段一定要是有序的或者是可排序的,否则问题就无法求解。
(2)确定状态和状态变量:将问题发展到各个阶段时所处于的各种客观情况用不同的状态表示出来。当然,状态的选择要满足无后效性。
(3)确定决策并写出状态转移方程:因为决策和状态转移有着天然的联系,状态转移就是根据上一阶段的状态和决策来导出本阶段的状态。所以如果确定了决策,状态转移方程也就可写出。但事实上常常是反过来做,根据相邻两段各状态之间的关系来确定决策。
(4)寻找边界条件:给出的状态转移方程是一个递推式,需要一个递推的终止条件或边界条件。
(5)程序设计实现:动态规划的主要难点在于理论上的设计,一旦设计完成,实现部分就会非常简单。