1.实践题目名称
7-1 最大子列和问题
2.问题描述
给定K个整数组成的序列{ N?1??, N?2??, ..., N?K?? },“连续子列”被定义为{ N?i??, N?i+1??, ..., N?j?? },其中 1≤i≤j≤K。“最大子列和”则被定义为所有连续子列元素的和中最大者。例如给定序列{ -2, 11, -4, 13, -5, -2 },其连续子列{ 11, -4, 13 }有最大的和20。现要求你编写程序,计算给定整数序列的最大子列和。
3.算法描述
一个序列的最大连续子段和,可能在该序列的左序列、右序列或中序列。用分治法解决。首先,分解子问题:把一个序列分解成三个子序列来解决,分别是左序列,右序列,和中序列。其次,求解“左序列的最大子段和” 与 “求解右序列”又可以看成是“和原问题相同”的子问题,用递归函数来实现求解;中序列则需要特殊考虑,可以从中间的那个元素分别向左、向右求和,最后把两个和加起来,就是中序列的最大子段和。最后,左、中、右序列的最大子段和,三者中最大的就是答案。
具体代码如下:
1 #include<iostream> 2 using namespace std; 3 4 int MaxSum(int a[],int left,int right) 5 { 6 int maxsum = 0; 7 8 //递归的变界条件 9 if(left == right){ 10 if(a[left] > 0){ 11 return a[left]; 12 } 13 else{ 14 return 0; //如果序列中所有整数皆为负数,则输出0 15 } 16 } 17 else{ 18 int mid = (left + right) / 2; 19 int leftsum = MaxSum(a, left, mid); //求左序列最大子段和 20 int rightsum = MaxSum(a, mid+1, right); //求右序列最大子段和 21 22 //求中间序列最大子段和 23 int left_border_sum = 0; 24 int s1 = 0; //临时累加器1 25 for(int i = mid; i >= left; i--) 26 { 27 s1 += a[i]; 28 if(s1 > left_border_sum) 29 { 30 left_border_sum = s1; 31 } 32 } 33 int right_border_sum = 0; 34 int s2 = 0; //临时累加器2 35 for(int i = mid+1; i <= right; i++) 36 { 37 s2 += a[i]; 38 if(s2 > right_border_sum) 39 { 40 right_border_sum = s2; 41 } 42 } 43 44 int midsum = left_border_sum + right_border_sum; 45 46 maxsum = leftsum > rightsum ? leftsum : rightsum; 47 maxsum = midsum > maxsum ? midsum : maxsum; 48 49 return maxsum; 50 } 51 52 } 53 54 int main() 55 { 56 int K,a[200005]; 57 cin>>K; 58 for(int i = 0; i < K; i++) 59 { 60 cin>>a[i]; 61 } 62 63 cout<<MaxSum(a, 0, K-1); 64 return 0; 65 }
4.算法时间及空间复杂度分析(要有分析过程)
时间复杂度分析:
①分解子问题:将原序列一分为二,时间复杂度为O(1)
②求解子问题:子问题的规模,是原来问题规模的一半;原问题分解为两个相同的子问题。所以时间复杂度为2T(n/2)
③合并子问题的解:每一次递归调用,就合并一次子问题的解。一共需要递归调用n/2次,所以时间复杂度为O(n)
解此递归方程可得,T(n) = O(nlogn)
空间复杂度分析:
空间复杂度为O(n),用于存储输入数据
5.心得体会(对本次实践收获及疑惑进行总结)
原文:https://www.cnblogs.com/z-qiong/p/13765267.html