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

 

使用动态规划求最大子数字和:
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)的复杂度么?

 

具体实现及思路如下:

 

 

  1 #include <cstdio>
  2 
  3 /*
  4 使用动态规划求最大子数字和:
  5 s[i]表示data[i~n-1]以元素i开始的最大子数组和,a[i]表示data[i~n-1]中的最大子数组和 ;
  6 s[i]=max(s[i+1]+data[i], data[i]);
  7 a[i]=max(a[i+1], s[i]); 
  8 
  9 由于数组s,a递推的时候,都只用到数组的前一个变量,所以可以用滚动数组节省空间。 
 10 */
 11 int maxSum(int data[], int n)
 12 {
 13     int s = data[n-1];
 14     int a = data[n-1];
 15     for(int i = n-2; i>=0; i--)
 16     {
 17         if(s<0)
 18             s=0;
 19         s+=data[i];
 20         if(s > a)
 21             a = s;
 22     } 
 23     return a;
 24 } 
 25 
 26 /*
 27 如果要求返回最大子数组和的位置,如何处理?
 28 使用curEnd记录当前最大字数组和的结束位置,
 29 当s(以元素i开始的最大子数组和) 小于零时,更新curEnd字数组末端标记,
 30 当a(当前的最大子数组和)发生变化时,更新最大字数组的标记Start,End 
 31 */ 
 32 int maxSum2(int data[], int n,int &start, int &end)
 33 {
 34     int s = data[n-1];
 35     int a = data[n-1];
 36     int curEnd = n-1;
 37     
 38     start = end = n-1;
 39     for(int i = n-2; i>=0; i--)
 40     {
 41         if(s<0)
 42         {
 43             s=0;
 44             curEnd = i;
 45         }        
 46         s+=data[i];
 47         if(s > a)
 48         {
 49             a = s;
 50             start = i;
 51             end = curEnd;
 52         }
 53             
 54     } 
 55     return a;
 56 } 
 57 
 58 /*
 59 如果数组arr[0],…,arr[n-1]首尾相邻,也就是允许找到一段数字arr[i],…,arr[n-1],arr[0],…,a[j],使其和最大,该如何?
 60 编程之美的答案的思路有问题,详见: http://www.ahathinking.com/archives/120.html
 61 参考该文算法,可知在允许数组跨界(首尾相邻)时,最大子数组的和为下面的最大值
 62 Maxsum={ 原问题的最大子数组和;数组所有元素总值-最小子数组和 }
 63 */ 
 64 int maxSum3(int data[], int n)
 65 {
 66     int maxs = data[n-1];
 67     int maxa = data[n-1];
 68     int sumAll = data[n-1];
 69     
 70     int mins = data[n-1];
 71     int mina = data[n-1];
 72     
 73     for(int i = n-2; i>=0; i--)
 74     {
 75         sumAll+=data[i];
 76         if(maxs<0)
 77             maxs=0;
 78         maxs+=data[i];
 79         if(maxs > maxa)
 80             maxa = maxs;
 81         
 82         if(mins>0)
 83             mins=0;
 84         mins+=data[i];
 85         if(mins < mina)
 86             mina = mins;
 87     } 
 88     int maxa2 = sumAll-mina;
 89     return maxa>maxa2?maxa:maxa2;
 90 } 
 91 
 92 
 93 int main()
 94 {
 95     /*
 96     int d[]={
 97         -4,-5,-6,-1,-5,-9
 98     };*/
 99     int d[]={
100         8,-10,60,3,-1,-6
101     };
102     int s,e;
103     int res = maxSum3(d,6);
104     printf("%d\n",res);
105 }

 

posted @ 2014-09-02 22:59  bigbigtree  阅读(365)  评论(0编辑  收藏  举报