zoukankan      html  css  js  c++  java
  • DP经典--百练2757--最长上升子序列

    题意描述

    有三种解法 n^2 和两个n*log(n)         一个讲得很好的博客:地址

    n^2的,动态规划:

    动归问题,首先很容易认为这道题的子问题就是,求前n个数字序列的解,这样的错误之处在于,“状态具有后效性”,前n个数字序列的解可能有多种,每一种可能结尾数字不一样,这样对后面的解就有了影响(后效性)

    比较好的子问题是,求以第n个数为结尾的数字序列的解,这样的子问题,便没有了后效性

    事实上,我认为第一种子问题如果加以处理也能消除后效性,但是我思考了一下觉得这样子会很麻烦,有兴趣的同学可以试试,一起讨论一下~

    确定了子问题剩下的就很简单

    ac代码:

    #include<iostream>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    using namespace std;
    
    #define maxn 1000+10
    #define inf 1<<31
    
    int dp[maxn],num[maxn];
    
    int main(){
        int n,ans=-1;
        cin>>n;
        for(int i=1;i<=n;i++){
            cin>>num[i];dp[i]=1;
            for(int j=1;j<i;j++){
                if(num[j]<num[i]){
                dp[i]=max(dp[i],dp[j]+1);
                }
            }
        }
        cout<<*max_element(dp+1,dp+n+1);
        return 0;
    } 

    n*log(n)的,贪心+二分:

    新建一个low数组,low[i]表示长度为i的LIS结尾元素的最小值。对于一个上升子序列,显然其结尾元素越小,越有利于在后面接其他的元素,也就越可能变得更长。因此,我们只需要维护low数组,对于每一个a[i],如果a[i] > low[当前最长的LIS长度],就把a[i]接到当前最长的LIS后面,即low[++当前最长的LIS长度]=a[i]。 
    那么,怎么维护low数组呢? 
    对于每一个a[i],如果a[i]能接到LIS后面,就接上去;否则,就用a[i]取更新low数组。具体方法是,在low数组中找到第一个大于等于a[i]的元素low[j],用a[i]去更新low[j]。如果从头到尾扫一遍low数组的话,时间复杂度仍是O(n^2)。我们注意到low数组内部一定是单调不降的,所有我们可以二分low数组,找出第一个大于等于a[i]的元素。二分一次low数组的时间复杂度的O(lgn),所以总的时间复杂度是O(nlogn)。

    ac代码:

    #include<cstdio>
    #include<algorithm>
    
    #define maxn 1000+10
    
    int lower[maxn],num[maxn]; 
    
    int main(){
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&num[i]);
        }
        int ans=1;
        lower[1]=num[1];
        for(int j=2;j<=n;j++){
         if(num[j]>lower[ans]){
             lower[++ans]=num[j];
         }
         else{
             int l=std::lower_bound(lower+1,lower+ans,num[j])-lower;
             lower[l]=num[j];
         }
        }
        printf("%d
    ",ans);
        return 0;
    }

    最后这种方法看起来比较麻烦,用到了树状数组,我还没有学到,篮桥北貌似也不考这个,因此以后在更吧~

    柳暗花明又一村
  • 相关阅读:
    Android ADB关闭Selinux ( adb shell setenforce 0 )
    通过windowmanager在camera界面上显示内容
    Android Handler类 发送消息-post()和postDelay(), Looper讲解
    Ubuntu下的log日志查看器
    Ubuntu下 安卓 adb 命令报:“insufficient permissions for device: user in plugdev group; ”问题的解决办法
    java.lang.UnsatisfiedLinkError: dlopen failed: library "/system/lib/libjni_i
    为 Linux 应用程序编写 DLL
    android Camera 之 ZSL
    Android Studio 导入 Android 系统模块并编译和调试
    微服务架构设计
  • 原文地址:https://www.cnblogs.com/ucandoit/p/8496086.html
Copyright © 2011-2022 走看看