算法第二章上机实践报告

                           7-1 最大子列和问题                                                           

给定K个整数组成的序列{ N1​​, N2​​, ..., NK​​ },“连续子列”被定义为{ Ni​​, Ni+1​​, ..., Nj​​ },其中 1。“最大子列和”则被定义为所有连续子列元素的和中最大者。

例如给定序列{ -2, 11, -4, 13, -5, -2 },其连续子列{ 11, -4, 13 }有最大的和20。现要求你编写程序,计算给定整数序列的最大子列和。

 

问题应这样解释:从给定一个数组中 ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),然后返回其最大和(应该是要大于等于零)。

int findmax(int *a,int left,int right)
{
    if(left==right) return a[left];
    
    int mid=(left+right)/2;
    int lmax=findmax(a,left,mid);
    int rmax=findmax(a,mid+1,right);
    
    int add=0,addl=a[mid],addr=a[mid+1];
    
    for(int i=mid;i>=left;i--)
    {
        add+=a[i];
        if(add>addl) addl=add;
    }
    add=0;
    for(int i=mid+1;i<=right;i++)
    {
        add+=a[i];
        if(add>addr) addr=add;
    }
    
    return maxnum(addl+addr,addl,addr);
}

 

View Code

函数 findmax 是核心递归代码,利用了递归分治的思想,每次递归进行三大步的操作,首先求出中点值,并从当前中心点向左搜索找出最大子序列和,然后从当前中心点向右搜索找出最大子序列和,最后以中心点下标分别向右和向左遍历找出最大子序列和,上述三者的最大值作为本层递归的返回值给上一层递归进行调用。实质上是从大(范围)到小(递归分解),再由小到大(返回求和)。

每次将问题分解为两个子问题,每个子问题的长度为原问题的一半,递归本身的时间复杂度最坏情况下应为为O(log2 n),最后一次找到要找的数;

对于n个元素的情况:

第一次二分:n/2
第二次二分:n/2^2= n/4
......
m次二分:n/(2^m)
在最坏情况下是在排除到只剩下最后一个值之后得到结果,所以为
n/(2^m)=1;
2^m=n;
 
且每次递归中,有有限个O(1)操作,有两个循环体,一个是从头到中间,另外一个是从中间到尾部, 所以加起来时间复杂度就是 O(n)。
所以时间复杂度为:O(n*logn);
 
空间复杂度为O(1);

 心得:这道题比较经典,能使用分治法的题目也是万变不离其宗,先要思考好若是使用递归算法,返回什么值,分治操作范围是由大到小(求精确值),还是先由大到小再由小到大(求和),每次递归中有哪些步骤,这些步骤的先后顺序,以及递归调用的参数如何设置,考虑好这些,使用分治法处理一些比较简单的问题就能很快的梳理好算法思想。

 

 
 
posted @ 2020-10-10 15:17  江鹏  阅读(120)  评论(0编辑  收藏  举报