最长上升子序列,最长下降子序列,最长公共子序列

文章介绍了如何使用二分查找优化求解最长上升子序列问题,以及动态规划解决最长公共子序列问题。对于最长上升子序列,通过比较当前元素与最长序列的末尾元素,更新最长序列;最长公共子序列则通过比较字符串对应位置的字符,动态规划计算最长长度。
摘要由CSDN通过智能技术生成

最长上升子序列(二分)

问题分析:求解给定数组a的最长上升子序列的长度。
子序列:一个给定序列的子序列是在该序列中删去若干元素后得到的序列
时间复杂度:O(nlogn)
核心代码:

for(int i=1;i<=n;i++)
{
    if(dp[cnt]<a[i]) dp[++cnt]=a[i];
    else *lower_bound(dp+1,dp+cnt+1,a[i])=a[i];
}

过程详解:

  1. for 循环遍历数组a,从索引1到索引n。
  2. if (dp[cnt] < a[i]) 判断当前元素a[i]是否大于最长上升子序列的最后一个元素。如果是,将a[i]添加到最长上升子序列的末尾,并更新计数器cnt的值。
  3. else 如果a[i]不大于最长上升子序列的最后一个元素,则使用 lower_bound 函数找到dp数组中第一个大于等于a[i]的元素的位置,然后将a[i]赋值给该位置,实现替换操作。

样例详解:
假设a数组为【2 1 3 2 3】,每一步的dp数组如下:

  1. 【2】
  2. 【1】
  3. 【1 3】
  4. 【1 2】
  5. 【1 2 3】

dp[i]的含义是:长度为i的上升序列中结尾最小的值。
因为这样更有利于我们在后面接上其他值,比如【1,2】和【2,3】,显然【1,2】后面可以接3,而【2,3】却不行。

最长下降子序列

原理同上
代码如下:

for(int i=1;i<=n;i++)
{
    if(dp[cnt]>a[i]) dp[++cnt]=a[i];
    else *lower_bound(dp+1,dp+cnt+1,a[i],greater<int>())=a[i];
}

最长公共子序列(动态规划)

问题分析:求解给定数组a和b的最长公共子序列的长度。
时间复杂度:O(NM),N和M分别代表a和b的长度。
核心代码:

f[i][j]=max(f[i-1][j], f[i][j-1]);
if(a[i]==b[j])
    f[i][j]=max(f[i][j], f[i-1][j-1]+1);

f[i][j]的含义是:字符串a的前i个字符和字符串b的前j个字符的最长公共子序列的长度。
核心代码的第一行表示状态转移方程:

f[i][j] = max(f[i-1][j], f[i][j-1])

它表示在考虑a[i]和b[j]字符时,最长公共子序列的长度要么等于字符串a的前i-1个字符和字符串b的前j个字符的最长公共子序列的长度,要么等于字符串a的前i个字符和字符串b的前j-1个字符的最长公共子序列的长度。即,我们要么选择不考虑a[i]字符,要么选择不考虑b[j]字符。

接下来的if语句用于处理当a[i]等于b[j]时的情况:

if(a[i] == b[j])
f[i][j] = max(f[i][j], f[i-1][j-1] + 1)

它表示如果a[i]等于b[j],那么最长公共子序列的长度可以在不考虑a[i]和b[j]的情况下加1。因此,我们在上述两个选择中选择更大的长度。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

真的卷

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值