zoukankan      html  css  js  c++  java
  • 【模板】最长上升子序列(LIS)及其优化 & 洛谷 AT2827 LIS

    最长上升子序列


    传送门


    题意

      对于给定的一个n个数的序列,找到它的一个最长的子序列,并且保证这个子序列是由低到高排序的。

    例如,1 6 2 5 4 6 8的最长上升子序列为1 2 4 6 8。

    基本思路

      非常显然,这类题用dp求解。 dp[i]表示已i为结尾的最长上升子序列的长度,首先枚举每一个末尾i,然后枚举从1到i-1,如果a[1...i-1]<a[i]说明满足上升子序列,就加上一后取max。

      附上代码。

     1 //LIS O(n^2)
     2 #include<iostream>
     3 using namespace std;
     4 int dp[100005],a[100005],n,maxx=-999;
     5 int main(){
     6     cin>>n;
     7     for(int i=1;i<=n;i++) cin>>a[i],dp[i]=1;
     8     for(int i=1;i<=n;i++){
     9         for(int j=1;j<i;j++){
    10             if(a[i]>a[j]) dp[i]=max(dp[i],dp[j]+1);//如果后面的大于前面的,就取较大的值。 
    11         }
    12         maxx=max(maxx,dp[i]);                    //每次更新最大值 
    13     }
    14     cout<<maxx;
    15     return 0;
    16 }
    O(n^2)代码

    优化

    //咕了八个半月的优化。。。。

    方法是把dp表示的意义倒过来:dp[i]表示长度为i的最长上升子序列的结尾元素最小是什么。

    很显然,dp数组一定是单调递增的。

    这时,对于每一个a[i],我们做出判断:

    • 当a[i]比当前最长的序列的最后一个数字还大,那么长度++;
    • 否则就二分查找dp数组中第一个>=a[i]的数值,并把它改为a[i]。

    为什么呢?

    因为这第一个大于等于a[i]的数的前一个数是最后一个小于a[i]的数,然后a[i]这个数就可以接到那个数的后面,又因为我们要保存的是最小值,就更新为a[i]。

     1 #include<iostream>
     2 #include<algorithm>
     3 using namespace std;
     4 const int maxn=100005;
     5 int n,dp[maxn],a[maxn],len;
     6 int main()
     7 {
     8     cin>>n;
     9     for(int i=1;i<=n;i++) cin>>a[i];
    10     for(int i=1;i<=n;i++){
    11         if(a[i]>dp[len]) dp[++len]=a[i];
    12         else{
    13             dp[lower_bound(dp+1,dp+len+1,a[i])-dp]=a[i];
    14         }
    15     }
    16     cout<<len;
    17     return 0;
    18 }
    O(nlogn)代码
  • 相关阅读:
    开源 免费 java CMS FreeCMS功能说明单位管理
    用Spring让Java Mail支持简化邮件发送
    Java Mail简化邮件发送+附件发送(源码奉上)
    java common practice to rethrow exceptions
    浅谈Java内存泄露
    全局样式
    求最大公约数和最小公倍数
    求所有水仙花数
    indexedDB数据库的使用
    fileReader读取文件
  • 原文地址:https://www.cnblogs.com/yinyuqin/p/10623886.html
Copyright © 2011-2022 走看看