N種方法妙講LIS演算法

2021-09-07 01:32:48 字數 3569 閱讀 3443

lis演算法經典彙總

假設存在乙個序列d[1..9] = 2 1 5 3 6 4 8 9 7,可以看出來它的lis長度為5。

下面一步一步試著找出它。

我們定義乙個序列b,然後令 i = 1 to 9 逐個考察這個序列。

此外,我們用乙個變數len來記錄現在最長算到多少了

首先,把d[1]有序地放到b裡,令b[1] = 2,就是說當只有1乙個數字2的時候,長度為1的lis的最小末尾是2。這時len=1

然後,把d[2]有序地放到b裡,令b[1] = 1,就是說長度為1的lis的最小末尾是1,d[1]=2已經沒用了,很容易理解吧。這時len=1

接著,d[3] = 5,d[3]>b[1],所以令b[1+1]=b[2]=d[3]=5,就是說長度為2的lis的最小末尾是5,很容易理解吧。這時候b[1..2] = 1, 5,len=2

再來,d[4] = 3,它正好加在1,5之間,放在1的位置顯然不合適,因為1小於3,長度為1的lis最小末尾應該是1,這樣很容易推知,長度為2的lis最小末尾是3,於是可以把5淘汰掉,這時候b[1..2] = 1, 3,len = 2

繼續,d[5] = 6,它在3後面,因為b[2] = 3, 而6在3後面,於是很容易可以推知b[3] = 6, 這時b[1..3] = 1, 3, 6,還是很容易理解吧? len = 3 了噢。

第6個, d[6] = 4,你看它在3和6之間,於是我們就可以把6替換掉,得到b[3] = 4。b[1..3] = 1, 3, 4, len繼續等於3

第7個, d[7] = 8,它很大,比4大,嗯。於是b[4] = 8。len變成4了

第8個, d[8] = 9,得到b[5] = 9,嗯。len繼續增大,到5了。

最後乙個, d[9] = 7,它在b[3] = 4和b[4] = 8之間,所以我們知道,最新的b[4] =7,b[1..5] = 1, 3, 4, 7, 9,len = 5。

於是我們知道了lis的長度為5。

!!!!! 注意。這個1,3,4,7,9不是lis,它只是儲存的對應長度lis的最小末尾。有了這個末尾,我們就可以乙個乙個地插入資料。雖然最後乙個d[9] = 7更新進去對於這組資料沒有什麼意義,但是如果後面再出現兩個數字 8 和 9,那麼就可以把8更新到d[5], 9更新到d[6],得出lis的長度為6。

然後應該發現一件事情了:在b中插入資料是有序的,而且是進行替換而不需要挪動——也就是說,我們可以使用二分查詢,將每乙個數字的插入時間優化到o(logn)~~~~~於是演算法的時間複雜度就降低到了o(nlogn)~!

借助例題

problem description

某國為了防禦敵國的飛彈襲擊,發展出一種飛彈攔截系統.但是這種飛彈攔截系統有乙個缺陷:雖然它的第一發炮彈能夠到達任意的高度,但是以後每一發炮彈都不能超過前一發的高度.某天,雷達捕捉到敵國的飛彈來襲.由於該系統還在試用階段,所以只有一套系統,因此有可能不能攔截所有的飛彈.

怎麼辦呢?多搞幾套系統唄!你說說倒蠻容易,成本呢?成本是個大問題啊.所以俺就到這裡來求救了,請幫助計算一下最少需要多少套攔截系統.

input

輸入若干組資料.每組資料報括:飛彈總個數(正整數),飛彈依此飛來的高度(雷達給出的高度資料是不大於30000的正整數,用空格分隔)

output

對應每組資料輸出攔截所有飛彈最少要配備多少套這種飛彈攔截系統.

sample input

8 389 207 155 300 299 170 158 65

sample output 2

經典lis演算法,與求最大上公升子串行相似:

以陣列 h 記錄攔截系統當前的攔截高度,先初始化為最大值 inf = 30000+10,

表示每乙個新攔截系統都能攔截所有的飛彈,然後遇到乙個飛彈就往前找看是否有已經使用了的系統能攔截,如果有,直接用;否則重新弄乙個系統。最後再看用了幾個系統就好了。

第乙個飛彈 389 < h[1] ( h[1] = inf)被第乙個系統攔截 h[1] = 389

第二個飛彈 207 < h[1] 被第乙個系統攔截 h[1] = 207

第三個飛彈 155 < h[1] h[1] = 155

第四個飛彈 300 > h[1] , 300 < h[2] ( h[2] = inf ) 所以新開發乙個系統攔截第四個飛彈, h[2] = 300

第五個飛彈 299 > h[1] , 299 < h[2] 被第二個系統攔截 h[2] = 299

第六個飛彈 170 > h[1] , 170 < h[2] h[2] = 170

第七個飛彈 158 > h[1] , 158 < h[2] h[2] = 158

第八個飛彈 65 < h[1] 被第乙個系統攔截 h[1] = 65

所以最後使用了兩個系統就攔截了所有的飛彈【遍歷 h陣列從 1到 n 看有幾個 != inf 就說明使用了】

飛彈高度:389 207 155 300 299 170 158 65

使用的攔截系統: 1 1 1 2 2 2 2 1

求最長上公升子串行:

給定排好序的一堆數列中,求其的lis長度。它的lis長度就是它非上公升子串行的個數。

此題可以用n種方法講解,下面一一為大家講解:

方法一:dp解法:

1 #include2

#define max(x,y) x>y?x:y

3int dp[10010],missile[10010];4

intmain()

12 max=max(max,dp[i]);13}

14 printf("

%d\n

",max);15}

16return0;

17 }

方法二:

二分法+貪心:

1 #include2

int missile[10010],lis[10010];3

intr;

4void search(int

x)11 lis[left]=x;12}

13int

main()

22 printf("

%d\n

",r);23}

24return0;

25 }

方法三:

stl+二分+貪心:

1 #include2 #include3

using

namespace

std;

4int lis[10010

]; 5

intmain()

15 printf("

%d\n

",r+1

);16}17

return0;

18 }

方法四:

vector+二分+貪心:

1 #include2 #include3 #include4

using

namespace

std;

5int

main()

15 printf("

%d\n

",lis.size());16}

17return0;

18 }

N種方法妙講LIS演算法

lis演算法經典彙總 假設存在乙個序列d 1.9 2 1 5 3 6 4 8 9 7,可以看出來它的lis長度為5。下面一步一步試著找出它。我們定義乙個序列b,然後令 i 1 to 9 逐個考察這個序列。此外,我們用乙個變數len來記錄現在最長算到多少了 首先,把d 1 有序地放到b裡,令b 1 2...

退出迴圈的n種方法

退出迴圈的n種方法,你能想出幾種?1 增加變數,作為退出條件 bool dobreak false for dobreak 2 使用goto for for outer 3 使用return void do lots of work void 4 巢狀if語句 bool isterminated f...

SQL 排序的N種方法

一 手工查詢得出名次 select select count 1 from t2 where t2.成績 t1.成績 as 名次 from t1 結果 1 2 3 3 5 二 sql server 2005 的排序函式 row number rank dense rank 1.row number ...