算法第二章上机实践报告

1.实践问题:求最大子段和问题

2.问题描述:

给定K个整数组成的序列{ N1​​, N2​​, ..., NK​​ },“连续子列”被定义为{ Ni​​, Ni+1​​, ..., Nj​​ },其中 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个子问题,从而只需求子问题的解,再递归得到原问题的解就会简单很多。也能大大降低时间复杂度。

posted @ 2020-10-08 20:46  陈茹容  阅读(101)  评论(0编辑  收藏  举报