输入格式:
包含N个整数num[i],描述了这段序列。
输出格式:
一个整数,为最大的子段和是多少。
思考:
若一个序列当中所有的数均为正数,那么最大字段和一定是这个序列当中所有的数的和。
但是如果这个数列当中存在着负数,那么情况就大不一样。如果要解决负数那么就需要用到动态规划,也就是常说的DP。
动态规划必然要素:状态,转移方程,初值,最终结果。
- 状态:dp_temp[i]表示在num序列当中的 i 个数当中,必须是以num[i]这个数结尾的子段和。
- 转移方程:dp_temp[i] = num[i] + max(0,dp_temp[i-1]) 这里是两种情况的判断:
- 若前dp_temp[i-1]小于等于0,换句话说就是以num[i-1]为结尾的字段和小于0,那么我们将这个字段和抛弃,直接取值为零,之后加上下一个数num[i];
- 若前dp_temp[i-1]大于0,那么我们可以再加上一个数,尝试着让他更大一些;
- 初始值:dp_temp[0]=0;
- 最终结果筛选:max(dp_temp[i])
样例代码:
dp_temp[0]=0;
int maxArraySum()
{
int ans=0;
for(int i=1;i<=n;i++)
{
dp_temp[i]=num[i]+max(0,dp_temp[i-1]);
ans=max(ans,dp_temp[i]);
}
return ans;
}
注:可能转移方程有些地方还是想不明白,下面我用例子来详细解释一下。
- 若一个n为7的数列,那么他的子序列一共有7!个而这么多个子序列我们并不需要全部遍历计算,只有当子序列和大于0的时候我们才会对他进行进一步操作,也就是加上下一个值,尝试将他变得更大。当然加上下一个值之前我们需要将当前的这个子序列的和 与之前已经算出来的序列和相比取较大的值。
- 当我们以num[i]为结尾构成状态序列时
- 若i=7,则dp_temp[7]就是num[7]结尾的序列和,换句话说7之前的所有子序列我们都已经遍历过了。为什么这么说呢,长度为7的子序列,其实是从长度为6的子序列加上第7个数组合而成。而我们不考虑前六个数每个数到底怎样,我们只关心它的和是否大于0,若大于0那么恭喜它,可以得到第7个数。否则以num[6]为结尾的子序列(也有可能不是以num[6]结尾,exp:1,-1,1,0,1,-1.其实是以num[3]结尾,等价于0,0,1.因为num[1],num[2]被抛弃,num[4:6]相当于被无视)只能被我们无情抛弃,用0来代替。
- 同理,若i=3,则在num[3]之前的所有子序列也就是num[1],num[2],num[1:2]被遍历过。num[1]是当i=1时遍历;num[2]是当num[1]<=0时被遍历;num[1:2]是当num[1]>0时被遍历。
tips:不用纠结于遍历所有子序列,因为有些子序列注定小于其他序列而被我们在判断的时候直接跳过。例如:1,2,3,4,5这个序列当中,1,2 ,3 这个序列注定大于 2, 3;也大于3,也大于2,这三个序列,只是因为前面的和大于0即可判定。