標籤:編程之美 數組最長遞增子序列 動態規劃
最近樓樓被男朋友帶著玩dota,有點上癮,終於在昨天晚上作出了一個重大的決定,shift+delete刪掉warIII檔案夾,從此退出dota的明爭暗鬥。不過最近看男票已經將戰場從11轉到了topcoder,嗯,這是個好現象,希望樓樓也能跟著玩兒起來。
理想是美好的,唉,可是樓主還在編程之美的初級階段啊。話不多說了,希望自己加油加油再加油!!(^o^)/~
今天要看的一道題目是求數組中最長遞增子序列。
題目簡介:
寫一個時間複雜度儘可能低的程式,求一個一維數組(N)個元素中的最長遞增子序列的長度。例如:在序列1, -1, 2, -3, 4, -5, 6, -7的最長遞增子序列的長度為4,這個子序列為1, 2, 4, 6.
注意:題目只要求求長度,不一定要求出這個遞增序列。
解法分析:
在這裡,要記住一個特別重要的點(對於像樓主這種渣渣),那就是滿足無後效性可以使用動態遞迴來解決。什麼叫無後效性,比如1, -1, 2, -3, 4, -5, 6, -7這個序列,當我們找到-1,2,當我們遍曆到元素4的時候,只需要比較4和2的關係,如果4比2大,那就可以加進去。而2之前的元素對於我們做決斷沒有任何影響,這就叫做“無後效性”。所以我們的解法是:
對於前面i個元素的任何一個遞增子序列,如果這個子序列的最大元素比array[i+1]小,那麼就可以將array[i+1]元素加在這個子序列後面,構成一個新的遞增子序列。
詳情請見代碼,演算法複雜度O(N^2),代碼中我有非常詳細的解釋,有什麼不明白的,請留言。
#include <iostream> #include <vector>using namespace std; int LIS (int *pArray, int len);int getMinOfArray (int *pArray, int len);int main() { int a[] = {2, -1, 2, -3, 4, 3, 1, 2, -7, 3, 4, 5, 6, 7, 8, 9}; int len = sizeof(a) / sizeof(int); vector<int> longestSubSequence; cout << "最大遞增序列的長度為" << LIS(a, len) << endl; system("pause");} int LIS (int *pArray, int len){ int *MaxV = new int[len + 1](); MaxV[1] = pArray[0]; MaxV[0] = getMinOfArray(pArray, len) - 1; int *LIS = new int[len](); //初始化最大遞增序列的資訊 for (int i = 0 ; i < len; i++) { LIS[i] = 1; } int nMaxLis = 1; for (int i = 0; i < len; i++) { int j; //下面代碼的作用是遞迴,看有沒有比最長遞增序列的最大元素的最小值大,如果有的話,那麼就可以直接加在後面了。然後最長遞增序列的個數加1 //比如,當i = 4, nMaxLis = 2,時,MaxV[2] = 2, a[i] = 4, 4 > 2, 那麼4可以加在2後面,遞增序列的元素個數加1。找到之後,直接break. for (j = nMaxLis; j >= 0; j--) { if (pArray[i] > MaxV[j]) { LIS[i] = j + 1; break; } } //如果i處的最大遞增序列,比原來的nMax大的話,那麼就更新啦。並且最長遞增序列的最大元素的最小值更新為當前元素 if (LIS[i] > nMaxLis) { nMaxLis = LIS[i]; MaxV[LIS[i]] = pArray[i]; } //如果沒有比原來的最大長度還長的話,那麼就有可能需要更新本長度最大元素的最小值了。比如,nMaxLis = 3的時候,前面我們找到的序列是{1, 2, 4}或者{-1, 2, 4} //當 i = 5時,j = 2時跳出迴圈。Lis[5] = 3 <= nMaxLis, 當時3比4小,所以nMaxLis = 3時最大元素的最小值由4更新為3. else if(MaxV[j] < pArray[i] && pArray[i] < MaxV[j + 1]) { MaxV[j + 1] = pArray[i]; } } delete []MaxV; delete []LIS; return nMaxLis;}//擷取數組元素的最小值int getMinOfArray(int *pArray, int len){ int result = pArray[0]; for (int i = 0; i < len; i++) { if (pArray[i] < result) { result = pArray[i]; } } return result;}
編程之美5:求數組中最長遞增子序列