日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

LIS(基于贪心的O(NlogN)解法)

發布時間:2024/9/3 编程问答 41 豆豆
生活随笔 收集整理的這篇文章主要介紹了 LIS(基于贪心的O(NlogN)解法) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

LIS:最長上升子序列,常規的dp解法,時間復雜度為O(N^2)
常規解法傳送門:https://blog.csdn.net/tb_youth/article/details/89354053
下面我要介紹的是更快的解法:
前提是不需要輸出這個最長子序列,只需確定最長子序列的長度;
解釋:
基于貪心策略,為了得到一個最長的上升子序列,前面的數越小,對后面上升子序列的長度就越有利

只需要模擬一個棧,最終結果為棧的長度,先把第一個元素壓入棧,對于后面的元素,只需要 先比較棧頂元素,如果比棧頂元素大就直接壓入棧,否則,在棧中 二分查找 第一個 比此時這個元素 大的元素,將 這個元素位置上的值 替換為 當前元素值,替換這一步就使前面的元素更小了,替換位置前的數沒有影響,替換位置上的數替換為當前數明顯是有利于后面上升子序列的增長(判斷當前元素時,棧內元素都是在此元素前面的)。
舉個栗子:
對于 (3, 1,3, 2,5,1, 6)
棧s:(為了方便從是s[1]開始,如果從s[0]開始,最終結果要+1)
先把第1個元素壓入棧,s[1] = 3;
從第2個元素1開始:
棧頂:s[1]
1 < s[1]
在棧中s(3),查找第一個大于它的元素:
此時找到的為s[1]
替換:s[1] = 1
棧中變為s(1)
(這里可以明顯看出更小的在前面更有利嘛)
第3個元素3:
3 > s[1]
直接壓棧s[2] = 3
棧頂更新為s[2],
s(1,3)
第4個元素2:
2 < s[2]
在棧中s(1,3)找第一個大于它的數,
找到的為s[2]
s[2]替換,s[2] = 2
棧中變為:s(1,2)
繼續:
第五個元素5
5 > s[2]
直接壓入,s[3] = 5
s(1,2,5)
第六個元素1
1 < s[3]
在棧中s(1,2,5)查找第一個大于它的數s:
查到為s[2]
s[2] = 1
棧中變為:s(1,1,5)
第七個元素6,
6 > s[3]
直接壓入棧,s(1,1,5,6)
結束。
最終在棧中的元素雖然不是對應的最長子序列,
但是我們每一步操作都讓我們后面增長遞增子序列更有利。
所以最終的長度一定是ans.

長度為4,ans = 4
代碼:

//貪心策略。O(NlogN)解法#include <stdio.h>int a[1005],s[1005];int main(){int n;scanf("%d",&n);int t = 0,l,r,m;for(int i = 1; i <= n; i++){scanf("%d",&a[i]);}s[++t] = a[1];for(int i = 2; i <= n; i++){if(a[i] > s[t]){s[++t] = a[i];}else{l = 1,r = t;//二分查找第一個大于a[i]的位置(也可以直接用upper_bound)//對于二分,這里一定是l<=r,why?如果換成<,在1,2,3中,二分找2你就會明白while(l <= r) {m = (l+r)/2;if(a[i] > s[m]){l = m + 1;}else{r = m - 1;}}s[l] = a[i];}}printf("%d\n",t);return 0;}

總結

以上是生活随笔為你收集整理的LIS(基于贪心的O(NlogN)解法)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。