求最大子列和
阿新 • • 發佈:2022-03-01
求最大子列和
給定\(N\)個整數的序列\({A_1,A_2,\cdots,A_N}\),求函式\(f(i,j)=\max{\{0,\sum_{k=i}^jA_k\}}\)
演算法一
int MaxSubseqSum1(int A[], int N) {/*三重巢狀迴圈,時間複雜度是O(N^3)*/ int ThisSum, MaxSum = 0; int i, j, k; for (i = 0; i < N; i++) {/* i是子列左端位置*/ for (j = i; j < N; j++) {/*j是子列右端位置*/ ThisSum = 0; /*ThisSum是A[i]到A[j]的子列和*/ for (k = i; k <= j; k++) ThisSum += A[k]; if (ThisSum > MaxSum) /*如果剛得到的這個子列和更大*/ MaxSum = ThisSum; /*則更新結果*/ } } return MaxSum; }
演算法二
int MaxSubseqSum2(int A[], int N) {/*二重巢狀迴圈,時間複雜度是O(N^2)*/ int ThisSum, MaxSum = 0; int i, j; for (i = 0; i < N; i++) { ThisSum = 0; for (j = i; j < N; j++) { ThisSum += A[j]; /*對於相同的i,不同的j,只要在j-1次迴圈的基礎上累加1項即可*/ if (ThisSum > MaxSum) MaxSum = ThisSum; } } return MaxSum; }
演算法三
int Max(int a,int b,int c){ return a>b?(a>c?a:c):(b>c?b:c); } int MaxSubseqSum3(int A[],int left,int right){//分而治之法,時間複雜度為O(NlogN) int MaxLeftSum,MaxRightSum;//存放左右子問題的最大和 int MaxLeftBorderSum,MaxRightBorderSum;//存放跨分界線的最大和 int LeftBorderSum,RightBorderSum;//存放跨分界的子列和 int center,i;//存放left和right的中線 if(left==right){ //當子列中只有一個數時停止遞迴 if(A[left]>0) return A[left]; else return 0; } //分而治之之一“分” center=(left+right)/2 ;//求left和right的中線 //遞迴返回兩邊的子列最大和 MaxLeftSum=MaxSubseqSum3(A,left,center); MaxRightSum=MaxSubseqSum3(A,center,right); //求跨分界線的最大子列和 MaxLeftBorderSum=0; MaxRightBorderSum=0; for(i=center;i>=left;i--){ //從中線向左掃描 LeftBorderSum+=A[i]; if(LeftBorderSum>MaxLeftBorderSum) MaxLeftBorderSum=LeftBorderSum; } MaxRightBorderSum=0; RightBorderSum=0; for(i=center+1;i<=right;i++){ //從中線向右掃描 RightBorderSum+=A[i]; if(RightBorderSum>MaxRightBorderSum) MaxRightBorderSum=RightBorderSum; } return Max(MaxLeftSum,MaxRightSum,MaxLeftBorderSum+MaxRightBorderSum); }
遞迴演算法:
\(O(N)=O(\frac N2)+O(\frac N2)+cN=2O(\frac N2)+cN\\=2^kO(1)+ckN\)
其中\(N/2^k=1\),所以\(2^k=N\),\(k=\log_2{N}\),所以\(O(N)=NO(1)+cN\log_2N=O(N\log N)\)
演算法四
int MaxSubseqSum4(int A[], int N) {//線上處理,時間複雜度為O(N)
/*
* “線上”的意思是指每輸入一個數據就進行及時處理,在任何一個地方中止輸入,演算法都能正確給出當前的解
*/
int ThisSum, MaxSum;
int i;
ThisSum = MaxSum = 0;
for (i = 0; i < N; i++) {
ThisSum += A[i];//向右累加
if (ThisSum > MaxSum) //發現更大和則更新當前結果
MaxSum = ThisSum;
else if (ThisSum < 0) //如果當前子列和為負數
ThisSum = 0; //則後面加上負數不可能是最大,所以拋棄該子列和
}
return MaxSum;
}