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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

lis最长上升子序列o(nlogn)优化

發布時間:2024/7/5 编程问答 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 lis最长上升子序列o(nlogn)优化 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

LIS的暴力算法

我們知道,LIS(最長上升子序列,最長下降子序列,最長不上升子序列,最長不下降子序列)如果按照最初得方法做,我們設置的狀態f[i]表示i結尾的最長LIS的長度,在枚舉每一個數的時候都要向前找一個數字,那么這種方法是O(n^2).(具體講解看這里)


優化后的LIS

如果N≤700000呢?O(n^2)的算法顯然是不符合要求的,我們可以考慮優化LIS的DP
我們以最長上升子序列為例:
我們設f[i]為長度為i的最長上升子序列結尾的最小個數.
那么,我們在枚舉新的數字a[i]的時候,如果a[i]要比枚舉的f[j]大,則說明以a[i]結尾必然能夠形成長度為j+1的最長上升子序列.我們可以選擇來模擬這個過程.
設這串序列為{2,1,6,5,8,0,1,5,10}
1.因為沒有數字,f[]={2}
2.因為1比2小,1無法接在任何數字后面,所以替代2,f[]={1}
3.因為6比任何一個數都要大,所以接在最前面,f[]={1,6}
4.5可以接在1后面并且比6要小,以此代替6,f[]={1,5}
5.因為8比任何數要大,接在末尾,f[]={1,5,8}
6.0比任何數都要小,所以f[]={0,5,8}
7.1可以接在0后面,所以f[]={0,1,8}
8.5可以接在8后面,所以f[]={0,1,5}
9.10可以接在5后面,所以f[]={0,1,5,10}
因為f[4]不為0,說明可以構成長度為4的最長上升子序列,故答案為4
為什么我們要在新的數字要是f[]數組內的原有值最小?因為這樣更可以讓后面的數字構成最長上升組序列.因此我們需要在這個序列中查找,找到一個位置使得前面的數比它小并且后面的數字大于等于它,使得它能夠覆蓋這個數字.那么,這個算法的時間復雜度仍然后O(n^2),顯然無法優化.
不難發現,這個序列是單調遞增的,那么我們便可以選擇在查找的時候去優化,在單調遞增的序列中我們可以需用二分查找去尋找那個可以覆蓋的位置,而二分查找的時間復雜度是O(lgn),再加上枚舉1-n的時間復雜度,故總復雜度為:O(n)*O(logn)=O(nlogn),顯然可以做到.
再重新說一下大致思路:
1.枚舉a[1...n]這些數字
2.如果這個數組比f數組末尾的數子要大,說明不能覆蓋任何一個數字,則放在最后
3.否則,用二分查找進行查詢位置并進行覆蓋.
同理,另外3中LIS也可以實現.
有一個需要注意的地方,那就是:如果做上升的和不下降的LISf[0]需要賦值為-∞,否則賦值為+∞,我在這里用pow(10,9)(即10的9次方的意思)在進行f[0]的初始化.因為可能會出現負數


LIS模板題

有N個整數,輸出這N個整數的最長上升序列、最長下降序列、最長不上升序列和最長不下降序列。
根據上述分析,我們應該十分容易就能夠寫出最后的程序,四個序列的代碼基本相似
代碼如下:

#include<bits/stdc++.h> using namespace std; int n; int a[800000]; int f[800000]; void Lis1() {memset(f,0,sizeof(f));int len=0,pos;f[0]=-pow(10,9);for (int i=1;i<=n;i++){if (a[i]>f[len]) f[++len]=a[i];else{int L=1,R=len,Mid;while (L+1<R){Mid=(L+R)>>1;if (a[i]>f[Mid]) L=Mid;else R=Mid;}if (a[i]>f[L]) pos=R;else pos=L;f[pos]=min(f[pos],a[i]); }}cout<<len<<endl; } void Lis2() {memset(f,0,sizeof(f));int len=0,pos;f[0]=pow(10,9);for (int i=1;i<=n;i++){if (a[i]<f[len]) f[++len]=a[i];else{int L=1,R=len,Mid;while (L+1<R){Mid=(L+R)>>1;if (a[i]<f[Mid]) L=Mid;else R=Mid;}if (a[i]<f[L]) pos=R;else pos=L;f[pos]=max(f[pos],a[i]);} }cout<<len<<endl; } void Lis3() {memset(f,0,sizeof(f));int len=0,pos;f[0]=pow(10,9);for (int i=1;i<=n;i++){if (a[i]<=f[len]) f[++len]=a[i];else{int L=1,R=len,Mid;while (L+1<R){Mid=(L+R)>>1;if (a[i]<=f[Mid]) L=Mid;else R=Mid;}if (a[i]<=f[L]) pos=R;else pos=L;f[pos]=max(f[pos],a[i]); }}cout<<len<<endl; } void Lis4() {memset(f,0,sizeof(f));int len=0,pos;f[0]=-pow(10,9);for (int i=1;i<=n;i++){if (a[i]>=f[len]) f[++len]=a[i];else{int L=1,R=len,Mid;while (L+1<R){Mid=(L+R)>>1;if (a[i]>=f[Mid]) L=Mid;else R=Mid;}if (a[i]>=f[L]) pos=R;else pos=L;f[pos]=min(f[pos],a[i]); } }cout<<len<<endl; } int main() {ios::sync_with_stdio(false);cin>>n;for (int i=1;i<=n;i++)cin>>a[i];Lis1();Lis2();Lis3();Lis4();return 0; }

轉載于:https://www.cnblogs.com/pigzhouyb/p/10119863.html

總結

以上是生活随笔為你收集整理的lis最长上升子序列o(nlogn)优化的全部內容,希望文章能夠幫你解決所遇到的問題。

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