最長上升子序列

算法簡述

最長上升子序列(Longest Increasing Subsequence, 簡稱LIS)是dp中比較經(jīng)典的一個(gè)算法模型, 它有一種樸素的算法O(n^2)和一種優(yōu)化版的算法(nlogn)實(shí)現(xiàn), 通過它, 我們可以進(jìn)一步了解dp的思想.

題目鏈接

pku-2533 Longest Ordered Subsequence

題意

給定一個(gè)長度為1000以內(nèi)的數(shù)組,每個(gè)元素范圍都在[0,10000]的整數(shù),求這個(gè)數(shù)組的LIS.

解法

記數(shù)組為a[0...n-1],算法很直接,具體如下:

  1. 狀態(tài)定義:
    dp[i]代表以第i項(xiàng)為結(jié)尾的LIS的長度.
  2. 狀態(tài)轉(zhuǎn)移:
    dp[i] = max(dp[i], max(dp[j]) + 1) if j < i and a[j] < a[i]
  3. 狀態(tài)初始化:
    dp[i]=1
  4. 時(shí)間復(fù)雜度:
    狀態(tài)數(shù)為n, 每次轉(zhuǎn)移復(fù)雜度是O(n), 所以算法總復(fù)雜度是O(n^2)

核心代碼:

for(i = 0; i < n; ++i) {
    for(j = 0; j < i; ++j) {
        if(a[j] < a[i]) {
            dp[i] = max(dp[i], dp[j] + 1);
        }
    }
}

完整代碼

算法優(yōu)化

再來看一道題:

題目鏈接:

hdu-1950 Bridging signals

題意:

這題是一個(gè)經(jīng)典的布線問題, 如下圖所示: 左右各有n(n<40000)個(gè)點(diǎn), 原本左邊的每個(gè)點(diǎn)分別跟右邊的一個(gè)點(diǎn)相連(不會(huì)有兩個(gè)左邊的點(diǎn)連同一個(gè)右邊的點(diǎn)), 要求我們拆除一部分線, 保留盡可能多的線, 使得剩下的線兩兩不能有交點(diǎn).

解法:

記左邊的兩個(gè)點(diǎn)為i, j且i < j, 與之相連的右邊的點(diǎn)分別為a[i], a[j], 則兩條線不相交的充要條件就是: a[i]<a[j], 于是這個(gè)問題轉(zhuǎn)化成了經(jīng)典的LIS.
但是這題與上題最大的差別就在于: 數(shù)組的長度太大了, 由1000變到了40000, 于是O(n^2)復(fù)雜度基本只有超時(shí)的命運(yùn), 所以我們必須想辦法優(yōu)化.

更優(yōu)的算法

下面介紹一種O(nlogn)的LIS算法:

  1. 記數(shù)組為a[0...n-1];
  2. 狀態(tài)定義:
    dp[i]代表LIS的第i項(xiàng)最小值, dpLen代表當(dāng)前dp數(shù)組的長度;
  3. 狀態(tài)轉(zhuǎn)移:
    dp初始為空數(shù)組, 我們按a數(shù)組元素的下標(biāo)順序進(jìn)行掃描, 假設(shè)現(xiàn)在掃描到a[i], 先找到dp數(shù)組中第一項(xiàng)大于或等于a[i]的元素, 記為dp[j]; 將dp[j]更新成a[i]即可; 如果dp數(shù)組中沒有元素比a[i]大的話, 那么直接將a[i]插入到dp數(shù)組的尾部,再更新dp數(shù)組長度;
  4. 整個(gè)數(shù)組的LIS結(jié)果就是dpLen.
  5. 需要注意的是, 雖然dp數(shù)組最終長度就是LIS, 但是里邊的元素并不是真正的子序列, 如果要求輸出這個(gè)序列, 加上一些反向追蹤變量就能得到了. 但是如何求LIS的數(shù)量呢?
  6. 剛開始dp數(shù)組為空,顯然是單調(diào)遞增數(shù)組, 而后面的每一步替換或者尾部插入執(zhí)行都不影響其單調(diào)遞增的特性, 所以每次定位到dp[j]可以用二分法, 復(fù)雜度是 O(logn)
  7. 整體算法復(fù)雜度:
    狀態(tài)轉(zhuǎn)移次數(shù)為n, 每次狀態(tài)轉(zhuǎn)移代碼都是logn, 所以總復(fù)雜度為O(nlogn).

算法步驟示例:

假設(shè)a = [4, 2, 6, 3, 1, 5], 初始dp=[], 具體算法運(yùn)行步驟如下:

  1. a[0]=4 => dp=[4];
  2. a[1]=2 => dp=[2];
  3. a[2]=6 => dp=[2, 6];
  4. a[3]=3 => dp=[2, 3];
  5. a[4]=1 => dp=[1, 3];
  6. a[5]=1 => dp=[1, 3, 5];
    所以這個(gè)a數(shù)組的LIS就是len(dp)=3. 從運(yùn)行步驟里可以看出, 如果一個(gè)數(shù)很小, 可以作為LIS的頭部或者中部, 讓后面的數(shù)字更容易接到它后面, 以此增大LIS長度; 而一個(gè)數(shù)非常大, 則可以很容易接到LIS的尾部, 也一樣能增大LIS長度; 所以讓它們找準(zhǔn)自己的定位還是非常重要的.

核心代碼:

dpLen = 0;
for (i = 0; i < n; ++i) {
    int idx = lower_bound(dp, dp + dpLen, a[i]) - dp;
    dp[idx] = a[i];

    if (idx + 1 > dpLen) {
        dpLen = idx + 1;
    }
}

完整代碼
ps: Java里沒有提供類似lower_bound或者upper_bound
之類的方法, 還是挺遺憾的, 所以這題代碼就用C++了.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌地梨,老刑警劉巖多律,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件矩乐,死亡現(xiàn)場離奇詭異,居然都是意外死亡盲再,警方通過查閱死者的電腦和手機(jī)蛋济,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門棍鳖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來炮叶,“玉大人碗旅,你說我怎么就攤上這事【迪ぃ” “怎么了祟辟?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長侣肄。 經(jīng)常有香客問我旧困,道長,這世上最難降的妖魔是什么稼锅? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任吼具,我火速辦了婚禮,結(jié)果婚禮上矩距,老公的妹妹穿的比我還像新娘拗盒。我一直安慰自己,他們只是感情好锥债,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布陡蝇。 她就那樣靜靜地躺著痊臭,像睡著了一般。 火紅的嫁衣襯著肌膚如雪登夫。 梳的紋絲不亂的頭發(fā)上广匙,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音恼策,去河邊找鬼鸦致。 笑死,一個(gè)胖子當(dāng)著我的面吹牛戏蔑,可吹牛的內(nèi)容都是我干的蹋凝。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼总棵,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼鳍寂!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起情龄,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤迄汛,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后骤视,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鞍爱,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年专酗,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了睹逃。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡祷肯,死狀恐怖沉填,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情佑笋,我是刑警寧澤翼闹,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站蒋纬,受9級(jí)特大地震影響猎荠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蜀备,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一关摇、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧碾阁,春花似錦输虱、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽戈毒。三九已至,卻和暖如春横堡,著一層夾襖步出監(jiān)牢的瞬間埋市,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來泰國打工命贴, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留道宅,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓胸蛛,卻偏偏與公主長得像污茵,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子葬项,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 背景 一年多以前我在知乎上答了有關(guān)LeetCode的問題, 分享了一些自己做題目的經(jīng)驗(yàn)泞当。 張土汪:刷leetcod...
    土汪閱讀 12,724評(píng)論 0 33
  • 假設(shè)存在一個(gè)序列d[1..9] = 2 1 5 3 6 4 8 9 7,可以看出來它的LIS長度為5民珍。n下面一步一...
    Gitfan閱讀 337評(píng)論 0 0
  • 動(dòng)態(tài)規(guī)劃(Dynamic Programming) 本文包括: 動(dòng)態(tài)規(guī)劃定義 狀態(tài)轉(zhuǎn)移方程 動(dòng)態(tài)規(guī)劃算法步驟 最長...
    廖少少閱讀 3,256評(píng)論 0 18
  • 題目 給定一個(gè)整數(shù)序列襟士,找到最長上升子序列(LIS),返回LIS的長度嚷量。說明最長上升子序列的定義:最長上升子序列問...
    六尺帳篷閱讀 378評(píng)論 0 1
  • 女孩 我想告訴你 你要加油陋桂。也許 你現(xiàn)在經(jīng)歷著一些非常難受 痛苦的事。但你別忘了 終會(huì)有一天 著一些都會(huì)過去 成為...
    夏天_ysumvonnemer閱讀 255評(píng)論 2 0