求整數序列的子序列和的最大值
阿新 • • 發佈:2018-12-15
一.常規思路
int sum1(int a[], int n) { int i, j; int maxSum = 0,curSum; for (i = 0; i < n; i++) { curSum = 0;//curSum表示從i開始的某子序列的和 for (j = i; j < n; j++) { //累加從區間[i,j]內的整數和到cunSum中 //從i開始的序列長度依次為1、2、……、n-i curSum += a[j]; if (curSum > maxSum) maxSum = curSum; } } return maxSum; } 時間複雜度 T(n)=O(n^2);
二.優化方案一
設區間[i,k]為符合條件的子序列(j<k<n), 因為a[i]+…+a[j]<0, i ≤j < k,則:a[i]+…+a[k]<a[j+1]+…+a[k],產生矛盾,表示區間[i,k]不是符合條件的子序列,同時表示i作為起點的區間[i,i]、 [i,i+1]… [i,j-1]都處理過了,下一步就是考慮i+1作為起點 。
int sum2(int a[],int n) { int i, j; int maxSum = 0,curSum; for (i = 0; i < n; i++) { curSum = 0; for (j = i; j < n; j++) { curSum += a[j]; if (curSum > maxSum) maxSum = curSum; else if (curSum < 0) break;//退出內層迴圈,考慮i+1作為起點 } } return maxSu } 時間複雜度 T(n)=O(n^2);
三.進一步優化
思考是否需要考慮區間[i+1,j]中的位置m作為起點? 按演算法步驟:當考慮以i作為子序列起點時,一旦: a[i]+…+a[j]<0, (j>i),按處理過程有: 因為:a[i]+…+a[j-1] ≥ 0 所以:a[i]+…+a[m-1] ≥ 0 (i<m ≤j) ai , ai+1,…am-1,am,… aj-1, aj,…ak … an-1 如果區間[m,k]是符合條件的子區間,因為: a[i]+…+a[m-1] ≥ 0, (i<m ≤j) 則區間[i,k]中的數字之和具有更大值,產生矛盾,即不需要再考慮m作為起點的情況,這樣新的起點就可以一步跳到j+1,即i=j+1。
int sum3(int a[], int n) { int i = 0, begin = -1, end = -1, maxSum = 0,curSum; curSum = 0; for (j = i; j < n; j++) { curSum += a[j]; if (curSum > maxSum) { begin = i, end = j; maxSum = curSum; } else if (curSum < 0) { i = j + 1;//修改起點位置 curSum = 0;//重新累加 } } return maxSum; //區間下標範圍[begin,end], //[-1,-1]表示無正數 } 時間複雜度 T(n)=O(n)