最长递增子序列

这篇文章讲的很细:https://blog.csdn.net/lxt_Lucia/article/details/81206439

方法一:动态规划

  • 时间复杂度 n log ⁡ n n\log{n} nlogn
  • dp[i]:以第i个元素为结尾的子序列的最大长度
  • 状态转移方程: d p [ i ] = m a x ( d p [ j ] + 1 ) , 其 中 a r r [ i ] > a r r [ j ] , i > j dp[i]=max( dp[j]+1), 其中arr[i]>arr[j], i>j dp[i]=max(dp[j]+1),arr[i]>arr[j],i>j

方法二:动态规划+二分

注意,此方法只能用于求LIS的长度,如果需要求LIS,需要记录路径信息

  • d p [ i ] dp[i] dp[i],表示长度为i的LIS结尾元素的最小值
  • 算法思想:维护一个递增序列,让其每个位置的元素尽可能保持最小,这样就给后续添加递增元素让出了最大空间,其维护的最终结果不一定是LIS,但长度和LIS相同。
  • 维护一个路径信息,可以推出所有LIS中字典序最小的一个。
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
string str;

void f() {
    int len=str.size();
    vector<int>path(len);   //str中第i个元素,其若作为子序列末尾元素,则此子序列的长度为(path[i]+1)
    vector<char>dp;  //长度为(i+1)的子序列,末尾最小元素是dp[i]
    dp.push_back(str[0]);
    path[0]=0;
    for(int i=1;i<len;i++){
        //如果str[i]大于dp末尾元素,则添加该元素支dp
        if(str[i]>dp[dp.size()-1]){
            dp.push_back(str[i]);
            path[i]=dp.size()-1;  //记录path
        }else{
            //找到dp中第一个大于等于str[i]的元素,替换它
            int pos=lower_bound(dp.begin(),dp.end(),str[i])-dp.begin();
            dp[pos]=str[i];
            path[i]=pos;    //记录path
        }
    }
    //在path中,从右往左,进行遍历
    int cur=dp.size()-1;    //找最长递增子序列的
    string ans="";
    for(int i=path.size()-1;i>=0 && cur>=0;i--){
        if(cur==path[i]){
            ans=str[i]+ans;
            cur--;
        }
    }
    cout<<ans;
}

int main() {
    ios::sync_with_stdio(false);    //关闭和scanf printf的同步,加速cin,减少大量输入时的耗时
    cin >> str;
    f();
    return 0;
}

方法三:树状数组 或 线段树

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值