标签:log 很多 res ase 比较 空间复杂度 编写 bottom rip
1.实践问题:求最大子段和问题
2.问题描述:
给定K个整数组成的序列{ N?1??, N?2??, ..., N?K?? },“连续子列”被定义为{ N?i??, N?i+1??, ..., N?j?? },其中 1。“最大子列和”则被定义为所有连续子列元素的和中最大者。例如给定序列{ -2, 11, -4, 13, -5, -2 },其连续子列{ 11, -4, 13 }有最大的和20。现要求你编写程序,计算给定整数序列的最大子列和。
3.算法描述:
#include<iostream>
using namespace std;
int MaxSubSum(int*a,int l,int r);
int main()
{ int k;
int a[100000];
cin>>k;
for(int i=0;i<k;i++)
{
cin>>a[i];
}
cout<<MaxSubSum(a,0,k-1);//输出递归结果
return 0;
}
int MaxSubSum(int*a,int l,int r)
{ int sum=0;//最大子段和的结果
if(l==r)//递归终点
{
sum=a[l]>0?a[l]:0;}//当递归只剩一个数时,与0比较,若大于0则当次递归的最大子段和为该数,否则为0.
else{
int mid=(l+r)/2;//二分递归
int ls=MaxSubSum(a,l,mid);//ls为左边的最大子段和
int rs=MaxSubSum(a,mid+1,r);//rs为右边的最大子段和
int sl=0;
int lefts=0;//sl为当次递归的左边的最大子段和,利用lefts来求sl
for(int i=mid;i>=l;i--){
lefts+=a[i];
if(lefts>sl)
{
sl=lefts;}
}
int sr=0;
int rights=0;//sr为当次递归的右边的最大子段和,利用rights来求sr
for(int i=mid+1;i<=r;i++){
rights+=a[i];
if(rights>sr)
{
sr=rights;}
}
sum=sl+sr;//最大子段和为横跨左右的情况
if(sum<ls)
{
sum=ls;}//最大子段和为左最大子段和
if(sum<rs)
{
sum=rs;}//最大子段和为右最大子段和
return sum;
}
4.
时间复杂度:由主定理T(n)=2*T(n/2)+O(n)得O(nlogn)。2*T(n/2)是将问题分成左右两边两个规模为n/2的相同问题。O(n)是得到跨边界最大子列和,时间复杂度是O(n)。
空间复杂度:O(1),只用到了一个确定的数组。
5.这道实践题让我很好地理解了递归和分治,对于递归算法,对我来说其中的突破点是找到递归终点,接下来就会好办很多。对于一个复杂的问题,可以考虑将其分成规模较小的k个子问题,从而只需求子问题的解,再递归得到原问题的解就会简单很多。也能大大降低时间复杂度。
标签:log 很多 res ase 比较 空间复杂度 编写 bottom rip
原文地址:https://www.cnblogs.com/1905crr/p/13782661.html