POJ2533, 最長上升子序列(貪心+二分查找時間複雜度O(nlogn))

使用這種方法是對動態規劃方法的一種優化,在用動態規劃求解時,求到第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);
    }
}


發佈了31 篇原創文章 · 獲贊 12 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章