美文网首页
最长上升子序列(LIS)——动态规划

最长上升子序列(LIS)——动态规划

作者: 小菜变大菜 | 来源:发表于2019-10-27 16:40 被阅读0次

问题描述

  给定n个数字的序列,如11,3,6,9,13,14,18,12,15,2,16,20,8,19,问最长的上升序列长度是多少。
  上升序列,分为严格单调递增序列和单调不减序列。前者需满足序列L中,i<j,L[i]<L[j],而后者可取等号。例如,上述序列中存在一个递增序列{3,8,19},显然不是最长的上升子序列。

分析

  因为递增的判断是在原序列末尾元素基础上进行比较的,是动态规划典例。递推关系如下:
  对于每个元素s[i],向前找所有小于s[i]的元素。

  • 若存在s[j]<s[i](j<i),则dp[i] = max{dp[j]} + 1
  • 若不存在s[j]<s[i](j<i),则s[i]自身构成一个子序列,dp[i] = max{dp[k]},k为小于i的整数
    可以得出
    dp[1]=1, dp[2]=1, dp[3]=2, dp[4]=3, dp[5]=4, dp[6]=5, dp[7]=6, dp[8]=6, dp[9]=6, dp[10]=6, dp[11]=7, dp[12]=8, dp[13]=8, dp[14]=8

代码实现

#include <iostream>
#include <cstring>

using namespace std;
const int maxn = 205;
int s[maxn], dp[maxn];

int main()
{
    int n; cin >> n;
    for(int i=0;i<n;i++) cin >> s[i];
    memset(dp, 0, sizeof(dp));
    dp[0] = 1;
    int i;
    for(i=1;i<n;i++){
        int tem_max=0;
        for(int j=0;j<i;j++){
            if(s[j]<s[i]) tem_max = max(tem_max, dp[j]);
        }
        dp[i] = tem_max+1;
    }
    cout << dp[n-1];
    return 0;
}

  上面代码的复杂度为O(n^n),每次考虑一个元素都需要和它之前的数依次比较一遍,比较笨。我们思考是否可以用一个数组保存当前最佳的最长子序列,这样每次新加入一个数,只需将其与数组最后一个元素比较即可。
  这会引入一个问题,保存的最长上升子序列的数组是动态变化的,并且为贪心使尽可能更多的元素加入,需要不断修改数组元素为不改变大小关系的最小值
  例如,已有当前的最长子序列{3,6,9,13,14,18},当遇到12时,比较18>12,那么寻找数组中第一个大于12的元素将其替换。处理完12得到的子序列是{3,6,9,12,14,18},长度不变,需要特别注意的是,此序列不能代表真实的最长上升子序列,只是为求解序列长度提供的一种量化方法
  将复杂度降到O(nlgn),代码如下

#include <iostream>
#include <cstring>

using namespace std;
const int maxn = 205;
int s[maxn], lis[maxn];

int bi_search(int A[], int right, int left, int num){ //二分查找递增数列a[n]中第一个大于num的元素下标,并返回
    int mid;
    while(right<left){
        mid = (right+left)/2;
        if(num<=A[mid]) left = mid;
        else right = mid+1;
    }
    return left;
}
int main()
{
    int n; cin >> n;
    int maxl;
    for(int i=0;i<n;i++) cin >> s[i];
    memset(lis, 0, sizeof(lis));
    lis[0] = s[0]; maxl = 1; //maxl表示lis数组元素个数,即最长上升子序列长度
    for(int i=1;i<n;i++){
        if(lis[maxl-1]<s[i])
            lis[maxl++] = s[i];
        else if(lis[maxl-1]==s[i]) continue;
        else{
            int p = bi_search(lis, 0, maxl-1, s[i]);
            lis[p] = s[i];
        }
    }
    cout << maxl;
    return 0;
}

注意

  上面两个算法都不能直接求出最长上升子序列

相关文章

  • LintCode 最长上升子序列

    给定一个整数序列,找到最长上升子序列(LIS),返回LIS的长度。 说明 最长上升子序列的定义: 最长上升子序列问...

  • LintCode 最长上升子序列

    题目 给定一个整数序列,找到最长上升子序列(LIS),返回LIS的长度。 说明最长上升子序列的定义:最长上升子序列...

  • LintCode 最长上升子序列

    题目 给定一个整数序列,找到最长上升子序列(LIS),返回LIS的长度。说明最长上升子序列的定义:最长上升子序列问...

  • 76. 最长上升子序列

    描述 给定一个整数序列,找到最长上升子序列(LIS),返回LIS的长度。 说明 最长上升子序列的定义: 最长上升子...

  • 76. 最长上升子序列

    给定一个整数序列,找到最长上升子序列(LIS),返回LIS的长度。说明最长上升子序列的定义:最长上升子序列问题是在...

  • lintcode 最长上升子序列

    给定一个整数序列,找到最长上升子序列(LIS),返回LIS的长度。说明最长上升子序列的定义:最长上升子序列问题是在...

  • 动态规划算法

    动态规划算法 最长上升子序列

  • 最长上升子序列(LIS)——动态规划

    问题描述   给定n个数字的序列,如11,3,6,9,13,14,18,12,15,2,16,20,8,19,问最...

  • LintCode-最长上升子序列(LIS)

    最长上升子序列给定一个整数序列,找到最长上升子序列(LIS),返回LIS的长度。 样例给出 [5,4,1,2,3]...

  • 字符串

    1 最长无重复字符子串 2 最长上升子序列(动态规划) 3 最长公共子序列的长度(动态规划) 4 对于一个字符串,...

网友评论

      本文标题:最长上升子序列(LIS)——动态规划

      本文链接:https://www.haomeiwen.com/subject/jjopvctx.html