[算法导论]4.1-5最大连续子数组问题
在线性时间内非递归的求数组的最大连续子数组(连续和最大的子数组)。
题目给出思路为数组A[1...j+1]的最大和子数组,有两种情况:a) A[1...j]的最大和子数组; b) 某个A[i...j+1]的最大和子数组,但思考很久没有理解如何用这个思路设计线性时间算法,希望有人能给予指点。
(i点是使A[1]+..+A[i]为负的一个值?)
目前的思路是,最大子数组一定位于从某个正数开始,全部求和<=0的一段数组中
从其实点i到目标点j,从第一个正数开始截取尽量长的一段数组,从第一个正数起的最大子数组即为当前数组的最大子数组,若数组和为负,则不可能作为更长数组最大子数组的组成部分(因为还不如从零直接取第一个正数),因此清零数组和并从接下来的第一个正数重新截取。
1 #include<iostream> 2 using namespace std; 3 4 int A[100]; 5 int main(){ 6 int size; 7 cin>>size; 8 bool neg_flag=true;//当全为负数时返回最大值。 9 int neg_max=-1e10; 10 for(int i=0;i<size;i++){//输入并判断是否全为负。 11 cin>>A[i]; 12 if(A[i]>=0){ 13 neg_flag=false; 14 } 15 if(A[i]>neg_max){ 16 neg_max=A[i]; 17 } 18 } 19 if(neg_flag==true){ 20 cout<<"max is "<<neg_max<<" start from "<<neg_max<<" to "<<neg_max<<endl; 21 return 0; 22 } 23 int max=-1e10;//最大和。 24 int s=-1;//最大子数组起点。 25 int e=-1;//最大子数组终点。 26 int add=0;//扫描子数组和。 27 int i=0;//扫描子数组起点。 28 int j=0;//扫描子数组终点。 29 while(j<size){ 30 add+=A[j]; 31 if(add>=0){ 32 if(add>=max){ 33 max=add; 34 s=i; 35 e=j; 36 } 37 ++j; 38 } 39 else{ 40 ++j; 41 i=j; 42 if(j<size){ 43 add=0; 44 } 45 } 46 } 47 cout<<"max is "<<max<<" start from "<<A[s]<<" to "<<A[e]<<endl; 48 49 }
http://www.cnblogs.com/bakari/p/4809684.html?ptvd
根据bakari的博文,还有动态规划的方法,这里的思路似乎可以用来解释上面的代码,但是还是不太能理解动态规划法和区间法的区别到底是什么
sum[i+1] = Max(sum[i] + A[i+1], A[i+1])
化简之后,其实就是比较sum[i] ?> 0(sum[i] + A[i+1] ?> A[i+1])
1 /************************************************************************/ 2 /* 动态规划(对应着上面的贪心法看,略有不同) 3 求A[1...j+1]的最大和子数组,有两种情况: 4 1)A[1...j]+A[j+1]的最大和子数组 5 2)A[j+1] 6 dp递推式: 7 sum[j+1] = max(sum[j] + A[j+1], A[j+1]) 8 /************************************************************************/ 9 int MaxSubArraySum_dp(int arr[], int len) 10 { 11 if (len <= 0) 12 exit(-1); 13 int nMax = INT_MIN; 14 int sum = 0; 15 16 for (int i = 0; i < len; i ++) { 17 if (sum >= 0) 18 sum += arr[i]; 19 else 20 sum = arr[i]; 21 if (sum > nMax) 22 nMax = sum; 23 } 24 return nMax; 25 }