最大子陣列問題(動態規劃)--【演算法導論】
阿新 • • 發佈:2019-01-04
前些天學車...真是相當累啊,比上課累,現在終於可以休息了...
重新看《演算法導論》,不過這下可得認真看了,9個月不到就得去找工作了,與我同樣的大三黨們一樣加油咯...
《演算法導論》中引入這個問題是通過股票的購買與出售,將前一天的當天的股票差價重新表示出來,即轉為了一個最大子陣列的問題,具體內容我不多說,轉的內容是:
13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7
找到這連續的16個數裡面的連續和最大的子陣列;
書中練習部分說用設計非遞迴的,線性時間的演算法,我就YY為動態規劃處理了;
從陣列的左邊界開始,從左至右處理,記錄到目前為止已經處理過的最大子陣列。若已知A[1..j]的最大子陣列,基於如下性質將解擴充套件為A[1...j+1]的最大子陣列:A[1...j+1]的最大子陣列要麼是A[1...j]的最大子陣列,要麼是某個子陣列A[i...j+1](1<=i<=j+1)。在已知A[1...j]的最大子陣列的情況下,可以線上性時間內找出形如A[i...j+1]的最大子陣列;
思想上述都將出來了,只要將關鍵點寫出即可:
如果前面若干和<0,則其對後面子陣列相加無幫助,此時重置dp為array[i],並且記錄的起始位置重新標記;
if(dp[i - 1] <= 0) //前面的<0,直接丟棄
{
dp[i] = array[i];
temp = i; //記錄起始為止
}
否則,繼續往後延伸;
dp[i] = array[i] + dp[i - 1]; //往後求和
最後判斷最大子陣列值就行,同時標記起始與結束位置:
if(dp[i] > MaxSumSub) //找到到i為止的最大子陣列 { MaxSumSub = dp[i]; //最大... start = temp; //標記起始 end = i; //標記此時的結束位置 }
程式碼:
#include <iostream> using namespace std; int FindMaxSubarray(int array[], int length) { int start = 0, end = 0; //記錄最大子陣列的起始位置(在陣列中的下標) int MaxSumSub; //最大子陣列的值 int* dp = new int[length]; //動態規劃記錄 dp[0] = array[0]; //初始為第一個數 MaxSumSub = dp[0]; //最大值初始為第一個數 int temp = 0; // for(int i = 1; i < length; i++) { if(dp[i - 1] <= 0) //前面的<0,直接丟棄 { dp[i] = array[i]; temp = i; //記錄起始為止 } else dp[i] = array[i] + dp[i - 1]; //往後求和 if(dp[i] > MaxSumSub) //找到到i為止的最大子陣列 { MaxSumSub = dp[i]; //最大... start = temp; //標記起始 end = i; //標記此時的結束位置 } } cout<<"最大子序列的下標:"<<start<<"->"<<end<<endl; return MaxSumSub; } int main() { int a[] = {13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7}; //int a[] = {23, 4}; int length = sizeof(a) / sizeof(int); cout<<FindMaxSubarray(a, length); return 0; }
最大子序列即為{18, 20, -7, 12};
上述dp即為動態記錄尋找最大子陣列的過程,大家也可以進行輸出看一下;
歡迎大家指點,o(∩_∩)o