求輸入序列的最大子序列
阿新 • • 發佈:2018-12-25
問題:給出一個有限長度的實數序列,求出其子序列中和為最大的子序列值?
方法1:設定兩個迴圈遍歷序列,分別作為子序列的左右兩端,再加一個迴圈將子序列中所有項相加,最後演算法的時間複雜度為。
void maxSubList(int list[],int length) { int maxSublist = 0,l=0,r=0; int thisSubList = 0; int i ,j,k; for (i = 0; i < length; i++) { //定義序列左端 for (j = i; j < length; j++) { //定義序列右端 for (k = i; k < j; k++) { thisSubList += list[j]; //將序列從左端i加到右端j } if (thisSubList > maxSublist) { maxSublist = thisSubList; //更新最大序列 l = i; //記錄最大子序列的左右下標 r = j; } } } cout << maxSublist << endl; cout << l<<","<<r << endl; }
方法2:首先思考,演算法需要做的是遍歷所有的子序列,在遍歷過程中就可以將所有的子序列進行求和比較,然後更新最大子序列即可,所以第三個迴圈可以省去。最後演算法的時間複雜度為。
void maxSubList(int list[],int length) { int maxSublist = 0,l=0,r=0; int thisSubList = 0; int i ,j; for (i = 0; i < length; i++) { //定義序列左端 thisSubList = 0; for (j = i; j < length; j++) { //定義序列右端 thisSubList += list[j]; //將序列從左端i加到右端j if (thisSubList > maxSublist) { maxSublist = thisSubList; //更新最大序列 l = i; //記錄最大子序列的左右下標 r = j; } } } cout << maxSublist << endl; cout << l<<","<<r << endl; }
方法3:根據分治的思想,對序列進行劃分。最大子序列可以在左邊子式,可以在右邊子式,也可以是跨越中間的子式,然後將左右子式依次劃分,求子式中的最大子式。如圖所示:
int MaxSubList(int numL, int numR,int* list) { if (numL == numR) { return list[numL]; //定義最終的返回值 } int l = 0, r = 0; int numMid = (numL+numR)/2; int lMax = MaxSubList(numL, numMid, list);//回撥求左邊的最大子式 int rMax = MaxSubList(numMid + 1, numR, list);//回撥求右邊的最大子式 int midMax=0,sumL=list[numMid],sumR=list[numMid+1],sum=0; for (int i = numMid; i >=numL; i--) { sum += list[i]; if (sum > sumL) //計算中間部分的最大子式 sumL = sum; } sum = 0; for (int j = numMid + 1; j <= numR; j++) { sum += list[j]; if (sum > sumR) sumR = sum; } midMax = sumL + sumR; if (lMax > midMax) { midMax = lMax; //判斷最後的大小 } if (rMax > midMax) { midMax = rMax; } return midMax; }
最後演算法的時間複雜度為。
4、最後介紹一下線上處理演算法。線上處理的意思就是邊讀入資料邊進行判斷整理,在逐項累加的過程中判斷累加數列是否為負,若為負數,則加後面的項只會使後面的數變小,所以清空累加數列。然後判斷累加後的數列與之前記錄的最大數列之間的大小,最後得出結果。它的演算法複雜度為。
int MaxSubList(int* list,int length) {
int thisSum = 0, maxSum = 0,startNum=0,stopNum=0;
for (int i = 0; i < length; i++) {
thisSum += list[i]; //逐項累加
if (thisSum < 0) {
thisSum = 0; //判斷累加後的數列若為負數,則捨棄該累加數列
startNum = i + 1; //同時將子數列起始序號重置
}
if (thisSum > maxSum) {
maxSum = thisSum; //判斷累加後的數列若大於之前記錄的最大子數列,則對最大子數列進行更新
stopNum = i; //同時將子數列的終止序號重置
}
}
cout << startNum << "," << stopNum << endl;
return maxSum;
該演算法不僅時間複雜度最低,而且還能同時求出最大子數列的起始,是目前最優的演算法。