求最大子序列和及其位置(四种经典方法)

来源:互联网 发布:小欧工程师软件 编辑:程序博客网 时间:2024/06/05 03:28

算法部分

#include <iostream>#include <vector>using namespace std;//http://blog.163.com/kevinlee_2010/blog/static/169820820201010495438247///http://www.cnblogs.com/mingzi/archive/2008/07/22/1248793.html//http://www.richardma.org/blog/?p=167207//http://blog.csdn.net/smallacmer/article/details/7188234//s(tart)表示最大子序列的开始位置,e(nd)表示结束位置//这里如果有多于一个的最大子序列的时候,只记录开始位置最低的那个int s=0;int e=0;//穷举法,复杂度O(n^3)long maxSubSum1(const vector<int> &a){long maxSum=0;for (int i=0; i<a.size();i++){for (int j=i;j<a.size();j++){long thisSum=0;for (int k=i; k<=j; k++){thisSum+=a[k];}if (thisSum>maxSum){maxSum=thisSum;s=i;e=j;}}}return maxSum;}//也是穷举法,不过减去了上面的一些不必要操作O(n^2)  long maxSubSum2(const vector<int> &a){long maxSum=0;for (int i=0; i<a.size(); i++){long thisSum=0;for (int j=i; j<a.size(); j++){thisSum+=a[j];if (thisSum>maxSum){maxSum=thisSum;s=i;e=j;}}}return maxSum;}long max3(long a, long b, long c){if(a<b)a=b;if(a>c)return a;elsereturn c;}long maxSumRec(const vector<int> a, int left, int right){if(left == right){//其实这个基准值在后面计算的时候可以保证//在这里不必多此一举if(a[left]>0)return a[left];elsereturn 0;}int center=(left+right)/2;long maxLeftSum=maxSumRec(a,left,center);long maxRightSum=maxSumRec(a,center+1,right);//某段序列中,求含最右侧元素序列和的最大值long maxLeftBorderSum=0,leftBorderSum=0;for (int i=center; i>=left; i--){leftBorderSum+=a[i];if(leftBorderSum>maxLeftBorderSum){maxLeftBorderSum=leftBorderSum;s=i;}}//某段序列中,求含最左侧元素序列和的最大值long maxRightBorderSum=0,rightBorderSum=0;for (int j=center+1; j<=right; j++){rightBorderSum+=a[j];if(rightBorderSum>maxRightBorderSum){maxRightBorderSum=rightBorderSum;e=j;}}return max3(maxLeftSum,maxRightSum,maxLeftBorderSum+maxRightBorderSum);}//该方法我们采用“分治策略”(divide-and-conquer),相对复杂的O(NlogN)的解法//最大子序列可能在三个地方出现,或者在左半部,或者在右半部,//或者跨越输入数据的中部而占据左右两部分。前两种情况递归求解,//第三种情况的最大和可以通过求出前半部分最大和(包含前半部分最后一个元素)//以及后半部分最大和(包含后半部分的第一个元素)相加而得到。long maxSubSum3(const vector<int> &a){return maxSumRec(a,0,a.size()-1);}//如果a[i]是负数那么它不可能代表最有序列的起点,因为任何包含a[i]的作为起点的子//序列都可以通过用a[i+1]作为起点来改进。类似的有,任何的负的子序列不可能是最优//子序列的前缀。例如说,循环中我们检测到从a[i]到a[j]的子序列是负数,那么我们就可以推进i。//关键的结论是我们不仅可以把i推进到i+1,而且我们实际可以把它一直推进到j+1。long maxSubSum4(const vector<int> &a){long maxSum=0;long thisSum=0;int t=0;for (int j=0; j<a.size(); j++){thisSum+=a[j];if(thisSum>maxSum){maxSum=thisSum;s=t;e=j;}else if(thisSum<0){thisSum=0;t=j+1;}}return maxSum;}


 

测试程序

int main(){cout << "==================input========================" << endl << endl;vector<int> input;input.push_back(-2);input.push_back(11);input.push_back(-4);input.push_back(13);input.push_back(-5);input.push_back(-2);cout << "------------------maxSubSum1--------------------" << endl;cout << maxSubSum2(input) << endl;cout << "start:" << s << endl;cout << "end:" << e << endl;cout << "------------------maxSubSum2--------------------" << endl;cout << maxSubSum1(input) << endl;cout << "start:" << s << endl;cout << "end:" << e << endl;cout << "------------------maxSubSum3--------------------" << endl;cout << maxSubSum3(input) << endl;cout << "start:" << s << endl;cout << "end:" << e << endl;cout << "------------------maxSubSum4--------------------" << endl;cout << maxSubSum4(input) << endl;cout << "start:" << s << endl;cout << "end:" << e << endl;cout << "==================input2========================" << endl << endl;vector<int> input2;input2.push_back(-6);input2.push_back(2);input2.push_back(4);input2.push_back(-7);input2.push_back(5);input2.push_back(3);input2.push_back(2);input2.push_back(-1);input2.push_back(6);input2.push_back(-9);input2.push_back(10);input2.push_back(-2);cout << "------------------maxSubSum1--------------------" << endl;cout << maxSubSum2(input2) << endl;cout << "start:" << s << endl;cout << "end:" << e << endl;cout << "------------------maxSubSum2--------------------" << endl;cout << maxSubSum1(input2) << endl;cout << "start:" << s << endl;cout << "end:" << e << endl;cout << "------------------maxSubSum3--------------------" << endl;cout << maxSubSum3(input2) << endl;cout << "start:" << s << endl;cout << "end:" << e << endl;cout << "------------------maxSubSum4--------------------" << endl;cout << maxSubSum4(input2) << endl;cout << "start:" << s << endl;cout << "end:" << e << endl;return 0;}