• 最长上升子序列


    题目

    分析

    下图为y总的递推公式分析

    dp[i] 表示 开头到 i 处最长上升子序列的长度。思考递推公式,如何由小的状态推大状态?

    以第 i 个数结尾的上升子序列的构成:仅含 i 位置这一个数(意味着前面上升子序列)或者 若a[i - 1] < a[i] 时,dp[i - 1] + 1。由于dp[i]存放的是最长上升子序列,所以要找到从0 到 i - 1的最长子序列长度 再加上 i 处本身的元素。所以递推公式:

    dp[i] = max(dp[j]+1),j = 0,1,2....i-1,且有a[j] < a[i] 

    代码

     1 #include<iostream>
     2 #include<algorithm>
     3 using namespace std;
     4 
     5 int main(){
     6     int n;
     7     scanf("%d",&n);
     8     vector<int>a(n);//存放序列
     9     vector<int>dp(n,0);
    10     for(int i = 0;i < n;i++){
    11         scanf("%d",&a[i]);
    12     }
    13     for(int i = 0;i < n;i++){
    14         dp[i] = 1;//最长子序列只含有一个数
    15         for(int j = 0;j < i;j++){ //从头遍历到i-1找到最大单增子序列最大值
    16             if(a[j] < a[i]){
    17                 dp[i] = max(dp[i],dp[j] + 1);
    18             }
    19         }
    20     }
    21     int res = 0;
    22     for(int i = 0; i < n;i++){
    23         if(res < dp[i]) res = dp[i];
    24     }
    25     cout<<res;
    26     return 0;
    27 }

    时间复杂度  = 状态数 * 转移数量,状态数是n,转移数量因为每次要遍历下末位置之前的所以也为n

    所以时间复杂度为O(n2)

    如何存储打印最长子序列?重点掌握

    就是开个数组保存一下是如何转移的

    #include<iostream>
    #include<algorithm>
    #include<stack>
    using namespace std;
    
    int main(){
        int n;
        scanf("%d",&n);
        vector<int>a(n);//存放序列
        vector<int>g(n,0); //存放转移位置
        vector<int>dp(n,0);
        
        for(int i = 0;i < n;i++){
            scanf("%d",&a[i]);
        }
        for(int i = 0;i < n;i++){
            dp[i] = 1;//最长子序列只含有一个数
            g[0] = 0;//开始只有头元素
            for(int j = 0;j < i;j++){ //从头遍历到i-1找到最大单增子序列最大值
                if(a[j] < a[i]){
                    //dp[i] = max(dp[i],dp[j] + 1);
                    if(dp[i] < dp[j]+1){
                        dp[i] = dp[j] + 1;
                        g[i] = j;//记录是从哪一个转移过来的,就是最长子序列的上一个元素
                    }
                        
                }
            }
        }
     
        //找到最长子序列的尾部下标
        int res = 0;
        for(int i = 0;i < n;i++){
            if(dp[res] < dp[i])
                res = i;
        }
        int len = dp[res];
        int k = res;
        stack<int>s;
        for(int i = 1;i <= len;i++){
            s.push(a[k]);
            k = g[k];
        }
        while(!s.empty()){
            cout<<s.top()<<" ";
            s.pop();
        }
        
        return 0;
    }
  • 相关阅读:
    一次安装。net core的经历
    c# task 等待所有子线程执行完的写法
    .net 中的async,await理解
    dbeaver pgsql连接工具
    oracle 导出表结构和备注
    abp
    发布站点
    excel 拆分多个excel并保持
    重定向和反向代理的区别
    es6中的解构赋值
  • 原文地址:https://www.cnblogs.com/fresh-coder/p/14409816.html
Copyright © 2020-2023  润新知