1、实践题目名称

最大子列和问题

2、问题描述

给定K个整数组成的序列{ N1​​, N2​​, ..., NK​​ },“连续子列”被定义为{ Ni​​, Ni+1​​, ..., Nj​​ },其中 1ijK。“最大子列和”则被定义为所有连续子列元素的和中最大者。例如给定序列{ -2, 11, -4, 13, -5, -2 },其连续子列{ 11, -4, 13 }有最大的和20。现要求你编写程序,计算给定整数序列的最大子列和。

3、算法描述

将K个元素分为两部分,mid为中点,左边部分为(left,mid),右边部分为(mid+1,right)。递归求出这两部分的最大子列和。当算法涉及递归的时候,特别需要注意的是递归出口,在这里,递归的出口就是当只有一个元素的时候,若该值大于0,返回该值,小于等于0则返回0。而最大子列和可能出现的情况有三种,第一种在left到mid这个范围中,第二中在mid+1到right这个范围中,第三种就是跨界情况,假设范围为(i,j),其中i<=mid<=j,所以最大子列和取三者的最大值。

int MaxSum(int a[], int left, int right)
{
    if (left == right) 
    {
        if(a[left] < 0)
            return 0;
        return a[left];
    }

    int mid = (left+right)/2;  
    int lMax = MaxSum(a, left, mid);
    int rMax = MaxSum(a, mid+1, right);
    int sum = a[mid] + a[mid+1];
    int t = sum;
 
    for (int i = mid-1;i >= left; i--)
    {
        t += a[i];
        if (t > sum)
        {
            sum = t;
        }
    }
 
    t = sum;
    for (int i = mid+2; i <= right; i++) 
    {
         t += a[i];
        if (t > sum)
        {
            sum = t;
        }
    }
 
    if (lMax > sum) 
    {
        sum = lMax;
    }
 
    if (rMax > sum)
    {
        sum = rMax;
    }
    return sum;
}

 

4、算法时间及空间复杂度分析(要有分析过程)

拆分子数组分别求长度近乎一半的数组的最大子段和sum1, sum2,时间复杂度 2* T(n / 2),从中心点往两边分别分别找到最大的和,找到跨越中心分界点的最大子段和sum3 时间复杂度 O(n),那么总体时间复杂度是T(n) = 2 * T(n / 2) + O(n) = O(nlogn)。

因为需要用到数组n个元素,所以空间复杂度为O(n)。

5、心得体会(对本次实践收获及疑惑进行总结)

一开始做这道题的时候我不假思索地用了蛮力枚举法,但这方法耗时长,效率低,因此认真学习了分而治之法,学习到了二分法在提高效率上的重要性,并顺带复习了大一上学期学习的查找算法。在这过程中我最大的疑惑点是对跨中间界的解决,还需要多体会、理解和熟悉分而治之法的思路。

posted on 2020-12-20 16:51  calebJ  阅读(91)  评论(0编辑  收藏  举报