使用這種方法是對動態規劃方法的一種優化,在用動態規劃求解時,求到第i個元素的最長上升子序列時,是在前i-1個數中尋找比第i個元素小的且該數是長度最長的上升子序列的最後一個數,在其長度基礎上加一即爲到該元素的最長上升子序列。在這次查找中浪費了時間。所以可以在查詢中做優化。
如果使用一個數組 b[k] 記錄前i個數中的長度爲k的所有子序列中最小一個值最小的值,用len記錄當前最長的上升子序列的長度。爲什麼要記錄最小值呢?這裏就用到了貪心的思想,只有上升子序列中的最後一個值最小,纔有更大的機會去增加上升子序列的長度。
在讀到下一個數時,有兩種情況:
1: 這個數大於b[len],相當於在動歸方法中找到了比這個元素小且序列長度最長的數,然後++len,並把這個數存到b[len]裏面以方便下次計算。
2: 這個數小於或等於b[len],及這個數只能與b[len]前面的數組合出長度小於或等於len的上升子序列。這樣的話,在數組b中找出最接近且比這個數大的數記做b[tem],那麼這個數就可以替代b[tem]成爲當前長度爲tem的序列中尾數最小的元素。
最後掃描完所有數據時,len的值一定就是最長公共子序列的長度。
代碼如下:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 100010;
const int INF = 1 << 30;
int b[MAXN];
int main()
{
int n, i, tem;
while(scanf("%d", &n) != -1)
{
for(i = 0; i <= n + 1; i++)
b[i] = INF;
for(i = 0; i < n; i++)
{
scanf("%d", &tem);
int pos = lower_bound(b, b+i+1, tem) - b; //二分查找tem要插入的位置
b[pos] = tem; //更新單調棧
}
for(i = 0; b[i] != INF; i++); //求單調棧的長度
printf("%d\n", i);
}
}