LIS专题(板子)

引言

不知道为啥上次放在LCS最后的LIS转LCS的方法在上机题中WA掉了,匆忙之下复制粘贴了别人的板子,感觉很罪恶,还是得总结一下属于自己的板子

O(n 2)

  • 分析:我们假设dp[i]表示以arr[i]结尾的最长上升子序列的长度,那么dp[i]就有可能从任何满足 arr[j] < arr[i] 的dp[j]转移来,只需在dp[i]和dp[j] + 1之间取最大值就好了,而这只是对于arr中的任意i所做的操作,最后要得到结果,我们还得在dp[1]到dp[i]中挑出最大值,即为最终答案,详见代码(为了格式化代码,所有变量声明在全局):
输入
void scan(){
    for(int i = 1;i <= n;i++){
        scanf("%d", &arr[i]);
    }
}
初始化
void init(){
    ans = 0;
    for(int i = 1;i <= n;i++){
        dp[i] = 1;//刚开始每个以arr[i]结尾的最长子序列都只有arr[i],故长度为1
    }
}
DP
void DP(){
    for(int i = 1;i <= n;i++){
        for(int j = 1;j < i;j++){
            if(arr[j] < arr[i]){
                dp[i] = max(dp[i],dp[j] + 1);
            }
        }
        ans = max(ans,dp[i]);
    }
}
输出
void print(){
    printf("%d\n", ans);
}

O(nlogn)

  • 分析:我们这样想一下,在对arr数组扫描的过程中,如果一个单调上升子序列的最后一个元素越小,那么就越有利于在后面接上元素,那么单调上升子序列就会更容易变长,于是用一个low数组,low[i]记录长度为i的单调上升子序列的最后一个元素,可以证明,扫描进行到最后得到的low数组长度,就是最长上升子序列的长度。
  • 思路:对于每个arr[i],如果arr[i] > low[ans],则low[ans++] = arr[i],否则在low数组中找到第一个大于等于arr[i]的元素,然后用arr[i]替换之
输入
/*与上一个输入相同*/
初始化
void init(){
    ans = 1;//每个序列的最长上升子序列长度最小为
}
OP
void OP(){
    low[1] = arr[1];
    for(int i = 2;i <= n;i++){
        if(arr[i] > low[ans]){
            low[++ans] = arr[i];
        }
        else{
            int tmp = lower_bound(low + 1,low + ans,arr[i]) - low;//用lower_bound函数找到大于等于arr[i]的第一个元素
            low[tmp] = arr[i];
        }
    }
}
输出
/*与上一个输出相同*/

对比(十分明显)

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值