数组的最大连续子序列
今天在网上看到的这道题目:
一个有N个元素的整型数组arr,有正有负,数组中连续一个或多个元素组成一个子数组,这个数组当然有很多子数组,求子数组之和的最大值。例如:[0,-2,3,5,-1,2]应返回9,[-9,-2,-3,-5,-3]应返回-2。
开始感觉貌似也没有那么难,就直接想循环遍历+动态规划的方法写即可。O(n2)的复杂度,感觉略大,想到上次关于最大子矩阵方法适合的O(n)的方法,感觉这个问题肯定也有这样的解法。在网上搜罗了一下,果真有各种简单的方法,仔细一看,这些方法之间还有关联性,这真的是一种思维方式的不同。
在我以前的想法中,只要能解决问题就行了,但是最近看了很多资料,觉得很多东西都不是自己开始以为的那么简单,很多东西都是需要深入研究学习的,感觉自己真的有很多不懂的地方。只想对自己说:加油,zxh。
废话不多说,代码、详细注释和思维流程都在这里:
1 //根据动态规划方法,另外设置一个数组subSum[i][j]表示序列i-j的元素的和; 2 //由题意知道: 3 //subSum[i][j]=arr[j] i==j 4 //subSum[i][j]=subSum[i][j-1]+arr[j] j<j 5 //当arr[j]<0时候,subSum[i][j]<subSum[i][j-1]当前的max判断可以省略 6 int maxSubArr(int arr[],int len){ 7 int sum=INT_MIN,i,j,end; 8 if(len<=0) return sum; 9 int **subSum=(int**)malloc(sizeof(int*)*len); 10 for(j=0;j<len;j++) 11 { 12 subSum[j]=(int*)malloc(sizeof(int)*len); 13 } 14 15 for (i=1;i<len+1;i++)//不同长度 16 { 17 for(j=0;j<=len-i;j++)//不同起始下标 18 { 19 end=j+i-1; 20 if(end==j) 21 subSum[j][end]=arr[end]; 22 else 23 subSum[j][end]=arr[end]+subSum[j][end-1]; 24 if(arr[end]>0 )sum=max(sum,subSum[j][end]); 25 } 26 } 27 28 for(j=0;j<len;j++) 29 { 30 free(subSum[j]); 31 } 32 free(subSum); 33 34 return sum; 35 } 36 37 //DP求解方法 38 //可以对数组中最后那一个元素进行分析,arr[len-1],最长子序列跟这个arr[len-1]的关系: 39 //arr[len-1]就是所要求的最长子序列max=arr[len-1] 40 //arr[len-1]是最长子序列的结尾,则有max=arr[len-1]+max[len-2] 41 //arr[len-1]跟最长子序列无关,即max=arr[len-2] 42 //end[i]表示以arr[i]为结尾的所有子序列中和的最大值 43 //all[i]表示从0-i中的序列中和最大的子序列的和 44 //这个只是为了表达清楚,我们其实还可以进一步优化,减少空间复杂度 45 int maxSubArr2(int arr[],int len){ 46 int end[30],all[30]; 47 int i=0; 48 end[i]=all[i]=arr[0]; 49 for (i=1;i<len;i++) 50 { 51 end[i]=max(arr[i],end[i-1]+arr[i]); 52 all[i]=max(end[i],all[i-1]); 53 } 54 return all[i-1]; 55 } 56 //maxSubArr2的优化版本 57 int maxSubArr3(int arr[],int len){ 58 int end,all; 59 int i=0; 60 end=arr[0]; 61 all=arr[0]; 62 for (i=1;i<len;i++) 63 { 64 end=max(arr[i],end+arr[i]); 65 all=max(end,all); 66 } 67 return all; 68 } 69 //另一个改进版本 70 //由 71 //end=max(arr[i],end+arr[i]); 72 //all=max(end,all); 73 //这两句,我们可以看到,end是取的arr[i]和arr[i]+end的最大值,那这两个值只有在end<0的情况下才取arr[i] 74 //也就是当end<0时候就重新累加,丢弃掉原来的结果 75 //那么过程就出来了,就是一直累加,每当遇到累加和小于0的时候就从头开始 76 int maxSubArr4(int arr[],int len){ 77 int sum=arr[0],maxVal=INT_MIN; 78 int i=0; 79 for (i=1;i<len;i++) 80 { 81 if (sum<0) sum=arr[i]; 82 else sum+=arr[i]; 83 84 maxVal=max(sum,maxVal); 85 } 86 return maxVal; 87 }