求子数组之和的最大值——编程之美 2.14 扩展问题 正确实现

来源:互联网 发布:grace出血评分软件 编辑:程序博客网 时间:2024/05/16 15:03

使用动态规划计算子数组之和的最大值


s[i]表示data[i~n-1]以元素i开始的最大子数组和,a[i]表示data[i~n-1]中的最大子数组和 ;s[i]=max(s[i+1]+data[i], data[i]);a[i]=max(a[i+1], s[i]); 由于数组s,a递推的时候,都只用到数组的前一个变量,所以可以用滚动数组节省空间。 


扩展问题:

 1) 如果数组首尾相连,即允许找到一组数字(A[i],···,A[n-1], A[0],···, A[j]),请使其和最大,怎么办?(书中答案错误,可以使用旋转数组的方法,时间复杂度n2,本文参考别人的想法,实现的算法复杂度为n)


 2) 如果题目要求返回最大子数组的位置,算法应该如何改变?还能保持O(N)的复杂度么?


具体实现及思路如下:



#include <cstdio>/*使用动态规划求最大子数字和:s[i]表示data[i~n-1]以元素i开始的最大子数组和,a[i]表示data[i~n-1]中的最大子数组和 ;s[i]=max(s[i+1]+data[i], data[i]);a[i]=max(a[i+1], s[i]); 由于数组s,a递推的时候,都只用到数组的前一个变量,所以可以用滚动数组节省空间。 */int maxSum(int data[], int n){int s = data[n-1];int a = data[n-1];for(int i = n-2; i>=0; i--){if(s<0)s=0;s+=data[i];if(s > a)a = s;} return a;} /*如果要求返回最大子数组和的位置,如何处理?使用curEnd记录当前最大字数组和的结束位置,当s(以元素i开始的最大子数组和) 小于零时,更新curEnd字数组末端标记,当a(当前的最大子数组和)发生变化时,更新最大字数组的标记Start,End */ int maxSum2(int data[], int n,int &start, int &end){int s = data[n-1];int a = data[n-1];int curEnd = n-1;start = end = n-1;for(int i = n-2; i>=0; i--){if(s<0){s=0;curEnd = i;}s+=data[i];if(s > a){a = s;start = i;end = curEnd;}} return a;} /*如果数组arr[0],…,arr[n-1]首尾相邻,也就是允许找到一段数字arr[i],…,arr[n-1],arr[0],…,a[j],使其和最大,该如何?编程之美的答案的思路有问题,详见: http://www.ahathinking.com/archives/120.html参考该文算法,可知在允许数组跨界(首尾相邻)时,最大子数组的和为下面的最大值Maxsum={ 原问题的最大子数组和;数组所有元素总值-最小子数组和 }*/ int maxSum3(int data[], int n){int maxs = data[n-1];int maxa = data[n-1];int sumAll = data[n-1];int mins = data[n-1];int mina = data[n-1];for(int i = n-2; i>=0; i--){sumAll+=data[i];if(maxs<0)maxs=0;maxs+=data[i];if(maxs > maxa)maxa = maxs;if(mins>0)mins=0;mins+=data[i];if(mins < mina)mina = mins;} int maxa2 = sumAll-mina;return maxa>maxa2?maxa:maxa2;} int main(){/*int d[]={-4,-5,-6,-1,-5,-9};*/int d[]={8,-10,60,3,-1,-6};int s,e;int res = maxSum3(d,6);printf("%d\n",res);}







0 0
原创粉丝点击