zoukankan      html  css  js  c++  java
  • LIS最长上升子序列O(nlogn)算法

    正常的求LIS的方法是用dp来做,时间复杂度为O(n^2),但是面对一些题目的时候这个复杂度就有点高了,就去学了一下nlogn的解法。主要运用到了二分查找,stl里面的lower_bound 也可以。

    upper_bound(i) 返回的是键值为i的元素可以插入的最后一个位置(上界) 
    lower_bound(i) 返回的是键值为i的元素可以插入的位置的第一个位置(下界)

    先贴一发O(n^2)的代码

     1 #include <bits/stdc++.h>
     2 #define fi first
     3 #define se second
     4 #define pb push_back
     5 #define fio ios::sync_with_stdio(false);cin.tie(0);
     6 #define pii pair<int,int>
     7 #define vi vector<int>
     8 #define vc vector<char>
     9 #define mii map<int,int>
    10 #define si(a) scanf("%d",&a)
    11 #define ss(a) scanf("%s",&a)
    12 #define sl(a) scanf("%I64d",&a);
    13 #define slf(a) scanf("%lf",&a);
    14 #define CLEAR(a,b) memset(a,b,sizeof(a))
    15 #define pi acos(-1)
    16 
    17 const int INF=0x3f3f3f3f;
    18 const int N=2e5+5;
    19 
    20 typedef long long ll;
    21 typedef double db;
    22 typedef unsigned long long ull;
    23 using namespace std;
    24 int dp[N];
    25 int num[N];
    26 int n;
    27 
    28 void solve()
    29 {
    30     int res=0;
    31     for (int i=0;i<n;i++)
    32     {
    33         dp[i]=1;
    34         for (int j=0;j<i;j++)
    35         {
    36             if(num[j]<num[i])
    37             {
    38                 do[i]=max(dp[i],dp[j]+1);
    39             }
    40             res=max(res,dp[i]);
    41         }
    42     }
    43     cout<<res<<endl;
    44 }
    45 int main()
    46 {
    47     fio;
    48     int n;
    49     cin>>n;
    50     for (int i=0;i<n;i++)
    51     {
    52         cin>>num[i];
    53     }
    54     solve();
    55 }

    这个很好理解,对于O(nlogn)的解法我看了一些博客,里面比较重要的就是替换这个操作,每次找到一个比最后一个还要大的值的时候直接加入后面,碰到比最后面小的数字的时候往里面找第一个比它小的数字,替换掉后面一个。(语文不好。。。直接看例子吧)

    如2 5 3 4 9 7 8 10 很容易就能看出来它的LIS长度为6,最长的是 2 3 4 7 8 10。 

    具体步骤如下,2进入;5比2大,进入;此时因为3比5小,往里找,2比3小,3替换掉5;4比3大,4进入;9比4大,9进入;7比9小,往前找,4比7小,7替换掉9;后面都直接进入,得到LIS序列2 3 4 7 8 10。

    O(nlogn)的代码具体如下

     1 #include <bits/stdc++.h>
     2 #define fi first
     3 #define se second
     4 #define pb push_back
     5 #define fio ios::sync_with_stdio(false);cin.tie(0);
     6 #define pii pair<int,int>
     7 #define vi vector<int>
     8 #define vc vector<char>
     9 #define mii map<int,int>
    10 #define si(a) scanf("%d",&a)
    11 #define ss(a) scanf("%s",&a)
    12 #define sl(a) scanf("%I64d",&a);
    13 #define slf(a) scanf("%lf",&a);
    14 #define CLEAR(a,b) memset(a,b,sizeof(a))
    15 #define pi acos(-1)
    16 
    17 const int INF=0x3f3f3f3f;
    18 const int N=2e5+5;
    19 
    20 typedef long long ll;
    21 typedef double db;
    22 typedef unsigned long long ull;
    23 using namespace std;
    24 int ans[N];
    25 int num[N];
    26 
    27 int main()
    28 {
    29     fio;
    30     int n;
    31     cin>>n;
    32     for (int i=1;i<=n;i++)
    33         cin>>num[i];
    34     ans[1]=num[1];
    35     int len=1;
    36     for(int i=2;i<=n;i++)
    37     {
    38         if(num[i]>ans[len])
    39             ans[++len]=num[i];
    40         else
    41         {
    42             int pos=lower_bound(ans,ans+len,num[i])-ans;
    43             ans[pos]=num[i];
    44         }
    45     }
    46     for (int i=1;i<=len;i++)
    47     {
    48         cout<<ans[i]<<" ";
    49     }
    50     cout<<endl;
    51 }
    52 
    53 
    54 /*
    55 8
    56 2 5 3 4 9 7 8 10
    57 */

  • 相关阅读:
    Redis服务器配置
    Spark History Server配置使用
    CentOS7.3安装Nginx
    U盘安装CentOS7的最终解决方案
    iconfont_3种引用方式
    div+css 让一个小div在另一个大div里面 垂直居中
    JavaScript数组方法
    addEventListener()和removeEventListener()
    js获取网页高度
    Linux修改命令行样式
  • 原文地址:https://www.cnblogs.com/TheSilverMoon/p/9382107.html
Copyright © 2011-2022 走看看