1、实践题目名称
最大子列和问题
2、问题描述
给定K个整数组成的序列{ N1, N2, ..., NK },“连续子列”被定义为{ Ni, Ni+1, ..., Nj },其中 1≤i≤j≤K。“最大子列和”则被定义为所有连续子列元素的和中最大者。例如给定序列{ -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、心得体会(对本次实践收获及疑惑进行总结)
一开始做这道题的时候我不假思索地用了蛮力枚举法,但这方法耗时长,效率低,因此认真学习了分而治之法,学习到了二分法在提高效率上的重要性,并顺带复习了大一上学期学习的查找算法。在这过程中我最大的疑惑点是对跨中间界的解决,还需要多体会、理解和熟悉分而治之法的思路。