求子数组之和的最大值——编程之美 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 }