96 最长上升子序列LIS(Longest Increasing Subsequence)

1 题目

题目:最长上升子序列LIS(Longest Increasing Subsequence)
描述:给定一个整数序列,找到最长上升子序列(LIS),返回LIS的长度。

最长上升子序列的定义:
最长上升子序列问题是在一个无序的给定序列中找到一个尽可能长的由低到高排列的子序列,这种子序列不一定是连续的或者唯一的。

lintcode题号——76,难度——medium

样例1:

输入:nums = [5,4,1,2,3]
输出:3
解释:LIS 是 [1,2,3]

样例2:

输入:nums = [4,2,4,5,3,7]
输出:4
解释:LIS 是 [2,4,5,7]

2 解决方案

2.1 思路

  使用动态规划的方式解,将状态定义为表示跳到位置i的最长上升子序列长度,则在位置i能够与位置j构成更长的上升序列的条件下,位置i的最优值 = max(位置j的最优值 + 1, 上次记录的位置i的最优值),理清动态规划的四要素即可解出。

循环结束后,dp中末尾位置的值表示的是以位置i为尾部的最长上升序列的序列长度,题意要求的是所有最长上升序列的最大长度,所以答案不在dp数组中,而需要在循环中打擂台获得。

2.2 时间复杂度

  本题动态规划的多重循环是对同一维的下标进行的,相当于在一个耗时n的循环内嵌套了同为耗时n的循环,时间复杂度为O(n^2)。

2.3 空间复杂度

  使用了容量为n的数组,空间复杂度为O(n)。

3 源码

细节:

  1. 动态规划的四要素:状态、方程、初始化、答案。(四要素在之前的题目数字三角形1中有详细介绍)
  2. 状态:用dp[i]表示跳到位置i的最长上升子序列长度(该上升序列最后一个值即位置i上的值)。
  3. 方程:在位置i能够与位置j构成更长的上升序列的条件下,位置i的最优值 = max(位置j的最优值, 位置i原有的最优值)
  4. 初始化:所有的位置都以自身构成为长度为1的上升序列。
  5. 答案:dp[i]中保存的是以位置i为尾部最长上升序列的序列长度,而题意要求的是所有最长上升序列的最大长度,答案不在dp数组中,而需要在循环中打擂台获得。

C++版本:

/**
* @param nums: An integer array
* @return: The length of LIS (longest increasing subsequence)
*/
int longestIncreasingSubsequence(vector<int> &nums) {
    // write your code here
    if (nums.empty())
    {
        return 0;
    }

    // 状态:dp[i]表示跳到位置i的最长上升子序列长度(该上升序列最后一个值即i位置的值)
    // 初始化:所有的位置都以自身构成为长度为1的上升序列
    vector<int> dp(nums.size(), 1);

    // 因为最长上升序列不一定都是以数组最后一个数结尾,需要在循环外定义一个值保存在过程中比较出的最大值
    int maxLISLength = 0;
    
    for (int i = 0; i < dp.size(); i++)
    {
        for (int j = 0; j < i; j++)
        {
            // 方程:在位置i能够与位置j构成更长的上升序列的条件下,位置i的最优值 = max(位置j的最优值, 位置i原有的最优值)
            if (nums[i] > nums[j])
            {
                dp[i] = max(dp[j] + 1, dp[i]);
            }
        }
        maxLISLength = max(dp[i], maxLISLength); // 取以位置i结尾的最长序列长度和之前的最优值中较大者
    }

    return maxLISLength; // 答案:dp[i]中保存的是以位置i为尾部的最长上升序列的序列长度,题意是所有最长上升序列的最大长度
}

  1. 数字三角形:https://blog.csdn.net/SeeDoubleU/article/details/124678103 ↩︎

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值