【题目】给一串整数a[1…n],求出它和最大的子序列,即找出1<=i<=j<=n,使a[i]+a[i+1]+…+a[j]最大。 【思路】代码内 【代码】 //By proing [http://blog.youkuaiyun.com/proing] #include "stdafx.h" #include <iostream> using namespace std; //算法一(穷举): //思想:枚举所有的i和j,计算a[i]+…+a[j],选择最大的 //时间复杂度为O(n3),显而易见。 //另外还可以优化一下穷举法, //方法1,可以把相邻的正数负数归为一个数 //方法2,预处理s[i] = a[1]+a[2]+…+a[i] //a[i]+…+a[j] = (a[1]+…+a[j])–(a[1]+…+a[i-1]) = s[j]–s[i-1] int MaxSub_1(int *pArray,int count) { int max = *pArray; int sum; for(int i=0;i<count-1;i++) for(int j=i+1;j<count;j++) { sum = 0; for(int k =i;k<j;k++) { sum += pArray[k]; if(sum > max) max = sum; } } return max; } //算法二(分治): //将a[n]分成a[1...n/2]和a[n/2+1...n],则a[n]的最大字段和有三种情况: //(1)a[1...n]的最大子段和与a[1...n/2]的最大子段和相同 //(2)a[1...n]的最大子段和与a[n/2...n]的最大子段和相同 //(3)a[1...n]的最大子段和为a[i...j], 1<=i<=n/2,n/2+1<=j<=n //时间复杂度为 T(n)=2T(n/2)+O(n) -> T(n)=O(nlogn) //在第三个情况时,左边部分向左求最大值,右边部分向右求最大值, //这样左右两边相加才能取得最大的值。 int MaxSub_DIV(int *v,int l,int r) { int k,sum=0; if(l==r) return v[l]; else { int center=(l+r)/2; int lsum=MaxSub_DIV(v,l,center); int rsum=MaxSub_DIV(v,center+1,r); int s1 = v[center]; int lefts=0; for (k=center;k>=l;k--) //向左计算 { lefts+=v[k]; if(lefts>s1) s1=lefts; } int s2 = v[center+1]; int rights=0; for (k=center+1;k<=r;k++) //向右计算 { rights+=v[k]; if(rights>s2) s2=rights; } sum=s1+s2; if(sum<lsum) sum=lsum; if(sum<rsum) sum=rsum; } return sum; } //算法三,动态规划算法,谈心算法 //时间复杂度T(n)=O(n) int MaxSub_2(int *pArray,int count) { if(NULL == pArray) return -0xFFFF; int sum ; int max ; max = sum = *pArray; while(count -- != 0) { pArray++; if(sum < 0) sum = *pArray; else sum += *pArray; if(max < sum) max = sum; } return max; } int _tmain(int argc, _TCHAR* argv[]) { int aa[20] = {7,-1,3,-2, 11,-3, 5,0,67,7,-291}; cout<<MaxSub_1(aa,8)<<endl; cout<<MaxSub_2(aa,7)<<endl; cout<<MaxSub_DIV(aa,0,6)<<endl; return 0; }