zoukankan      html  css  js  c++  java
  • 动态规划——最长上升子序列

    问题

        最长上升子序列是一类经典的动态规划问题。

    给定N个数字, A1,A2,....An,从中选择k个数字 At1, At2,... Atk,满足 1 =< t1 < t2 < .. < tk <= n,且 At1 < At2 < ... < Atk,求满足要求的最大的k。

    分析

        设一个动归数组dp,dp[i]表示以第i个数字(即Ai)结尾的最长上升子序列的长度,显然这种问题的划分满足无后效性和最优子结构。同时,可以很方便的推出递推关系 
    dp[i] = max{1, dp[j] +1} (j < i 且 Ai > Aj)

    实现

    memset(dp, 0, sizeof(dp));
    for(int i = 1; i <= n; i ++){ //数组从1开始
        int max = 0;
        for(int j = 1; j < i; j ++){
            if(A[i] > A[j])
                dp[i] = max(dp[i], dp[j] + 1);
                if (dp[i] > max)
                    max = dp[j];
        }
    }    
    

    复杂度分析

        显然,时间复杂度为O(n^2), 空间复杂度为O(n).

     

    O(nlogn)复杂度解法

    其实还存在一种时间复杂度为O(n*logn)的算法,也是使用动态规划思想,状态 dp[p] 为 所有最长长度为p+1的上升子序列中最后一个元素的最小值。

    这样,从头到尾遍历数组nums,对于当前的nums[i],在dp中查找第一个比nums[i]大的数 dp[k],如果没找到,则dp数组的长度p增加1,并且设置dp[p] = nums[i],

    如果找到,则将 dp[k] 赋值为 nums[i](因为nums[i]是此时最长长度为k+1的上升子序列中最后一个元素的最小值)。

    最后dp数组的长度就是最长上升子序列的长度。

    int lengthOfLIS(vector<int>& nums) {
            int n = nums.size();
            if(n <= 0)
                return 0;
            vector<int> dp(n+1, 0);
            int len = 0;
            dp[len] = nums[0];
            for(int i = 1; i < n; i ++){
                vector<int>::iterator it = lower_bound(dp.begin(), dp.begin() + len + 1, nums[i]);
                if(it == dp.begin() + len + 1){
                    dp[++len] = nums[i];
                }else {
                     *it = nums[i];
                }
            }
            return len + 1;
    }
    

     

     

     

     

     

  • 相关阅读:
    20155215 第二周测试1 与 myod
    2017-2018-1 20155215 《信息安全系统设计基础》第1周学习总结
    第十四周 P187教材检查
    数据库1 实验代码和截图补交
    20155215 2016-2017-2《Java程序设计》课程总结
    20155215 宣言 实验五 网络编程与安全 实验报告
    实验MyOD
    Alpha冲刺——代码规范与计划
    您为何会咸鱼———项目系统设计与数据库设计
    您为何会咸鱼——团队 Gitee 实战训练
  • 原文地址:https://www.cnblogs.com/gtarcoder/p/4840829.html
Copyright © 2011-2022 走看看