码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • DP之字符串算法


    之前写的关于DP问题的一般分析思路:DP之01背包详解
    这篇的话主要是来学习常见的序列问题中用到的DP。

    文章目录

    • 第一种、最长上升子序列
      • 1.1 题目信息:
      • 1.2 分析:
        • 1.2.1 状态表示:
        • 1.2.2 确定状态转移方程
        • 1.2.3 边界:
      • 1.3 代码:
      • 1.4 最长不下降子序列:
    • 第二种:最长公共子序列(LCS)
      • 2.1 题目信息:
      • 2.2 分析:
        • 2.2.1 状态表示:
        • 2.2.2 状态转移方程:
        • 2.2.3 边界:
      • 2.3 代码:
    • 第三种、最长公共子串(LCS)
      • 3.1 题目信息:
      • 3.2 分析:
        • 3.2.1 状态表示:
        • 3.2.2 状态转移方程:
        • 3.2.3 边界:
      • 3.3 代码:

    第一种、最长上升子序列

    1.1 题目信息:

    1.2 分析:

    1.2.1 状态表示:

    f[i]记录所有以第i个数结尾的上升子序列

    1.2.2 确定状态转移方程

    如何更新f[i]的值呢?
    其实在这个类型的题目中是枚举以i为结尾的序列的上一个数是哪一个。于是我们需要变量j从1枚举到i-1,如果a[i]>a[j]并且f[i]>f[j]+1,那么我们认为这是可以用来更新f[i]的值。
    所以可以得出状态转移方程为:

    if(a[i]>a[j])//可以保证是上升序列
    	f[i]=max(f[i],f[j]+1);//通过不断的更新最终保证是最长上升序列
    

    1.2.3 边界:

    f[1]=1;

    1.3 代码:

    # 时间:2022.09.27  21点47分
    #include
    #include
    #include
    using namespace std;
    const int N=100;
    int a[N];
    int f[N];
    int main()
    {
        int n;
        cin>>n;
        for(int i=1;i<=n;i++) cin>>a[i];
        
        for(int i=1;i<=n;i++){
            f[i]=1;//单个数字也可以认为是长度为1的序列
            for(int j=1;j<i;j++)
                if(a[i]>a[j])//保证得到得到上升序列
                    f[i]=max(f[i],f[j]+1);//更新得到的保证是最长上升序列
        }
        int mmax=-1;
        for(int i=1;i<=n;i++)   mmax=max(f[i],mmax);
        cout<<mmax<<endl;
        return 0;
    }
    

    1.4 最长不下降子序列:

    在这里插入图片描述

    和最长上升序列的区别就是元素可以相同。
    只需要将核心代码 f[i] > f[j] 改为 f[i] >= f[j]即可

    第二种:最长公共子序列(LCS)

    2.1 题目信息:

    在这里插入图片描述

    2.2 分析:

    2.2.1 状态表示:

    ==f[i,j]:==所有在第 1个序列的前 i 个字母中出现,且在第二个序列的前 j 个字母中出现的子序列的集合的最大值。

    2.2.2 状态转移方程:

    这种情况下需要看a[i]和b[i]是否在公共序列中:

    1. 若a[i]=b[j],则a[i]与b[j]在公共子序列中,f[i][j]=f[i-1][j-1]+1
    2. 若a[i]!=b[j],且a[i]不在公共子序列中,则可去掉a[i],所以f[i][j]=f[i-1][j]
    3. 若a[i]!=b[j],且b[j]不在公共子序列中,则可去掉b[j],所以f[i][j]=f[i][j-1]
    4. 若a[i]!=b[j],且a[i]和b[j]都不在公共子序列中,则可去掉a[i]和b[j],所以f[i][j]=f[i-1][j-1] ,但是其实可以发现这种情况是包含在2和3中的,所以不用单独写出。

    转移方程:

    1. 如果a[i]!=b[j] 那么 f[i][j]=max(f [i-1] [j],f [i] [j-1] )
    2. 如果a[i]=b[j] 那么 f[i][j]=f [i-1] [j-1]+1

    2.2.3 边界:

    f[0][j]=0,f[i][0]=0;

    2.3 代码:

    // 时间:2022.07.13 17点48分
    #include
    #include
    using namespace std;
    
    const int N=1010;
    int n,m;
    char a[N],b[N];
    int f[N][N];
    int main()
    {
       cin>>n>>m;
       scanf("%s%s",a+1,b+1);
       
       for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        {
            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);
        }    
        cout<<f[n][m]<<endl;
        return 0;
    }
    

    第三种、最长公共子串(LCS)

    和最长公共子序列的区别:

    公共子串:字符必须是连续相等的
    公共子序列:字符必须是相等的,可以不连续

    3.1 题目信息:

    在这里插入图片描述

    3.2 分析:

    3.2.1 状态表示:

    只有当两字符串中的字符连续相等时,公共子串的长度才不断增加,否则清零
    状态表示:
    f[i][j]表示以a[i]和b[j]为结尾的公共子串的长度

    3.2.2 状态转移方程:

    我们可以先模拟一下样例:当i=1时
    在这里插入图片描述
    当i=2时:
    在这里插入图片描述
    转移方程:
    我们可以从中找出规律来:只有当a[i]和b[j]相等时才能构成字串,其余的情况都是都不行。

    1. 若a[i]=b[j],则可以构成公共子串,f[i] [j] = f [i-1 ][j-1] +1
    2. 若a[i]!=b[j],则不能构成公共子串,f[i][j] =0

    3.2.3 边界:

    f[0][j]=0
    f[i][0]=0

    3.3 代码:

    // 时间:2022.09.28 21点07分
    #include
    using namespace std;
    int f[100][100];
    int main ()
    {
        string a,b;
        cin>>a>>b;
        int mmax=-1;
        for(int i=1;i<=a.size();i++){
            for(int j=1;j<=b.size();j++){
                if(a[i-1]==b[j-1])//注意此时下标
                    f[i][j]=f[i-1][j-1]+1;
                else f[i][j]=0;
                if(f[i][j]>mmax) mmax=f[i][j];
                //在更新f数组的同时就可以将最大值找到
            }
        }
        cout<<mmax<<endl;
        return 0;
    }
    
  • 相关阅读:
    竣达技术 | 适用于”日月元”品牌UPS微信云监控卡
    MFC CArray类和鼠标连线程序
    Electron 进程间通信的四种方式
    OmniShade - Mobile Optimized Shader
    设计模式:备忘录模式
    科目三: 变道与超车
    探索Terraform实践:优化基础设施管理
    COO、CSR、adj_coo、adj_csr详解:稀疏矩阵与稀疏邻接矩阵的存储格式及转换
    Mathorcup数学建模竞赛第四届-【妈妈杯】C题:家庭暑假旅游套餐的设计(附MATLAB和SAS代码)
    您的开发团队是否面临效率陷阱?
  • 原文地址:https://blog.csdn.net/weixin_53051813/article/details/127079476
  • 最新文章
  • 【JVM】编译执行与解释执行的区别是什么?JVM 使用哪种方式?
    用 Hashids 优雅解决 C 端自增 ID 暴露问题
    V8引擎 精品漫游指南--Ignition篇(上) 指令 栈帧 槽位 调用约定 内存布局 基础内容
    LLVM Pass快速入门(四):代码插桩
    milkup:桌面端 markdown AI续写和即时渲染
    基于项目工程构建SBOM(软件物料清单)的研究
    鸿蒙应用开发UI基础第二节:鸿蒙应用程序框架核心解析与实操
    .NET 中如何快速实现 List 集合去重?
    扣子Coze实战:从0到1打造抖音+小红书热点监控智能体
    浅谈数据访问层
  • 热门文章
  • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
    奉劝各位学弟学妹们,该打造你的技术影响力了!
    五年了,我在 CSDN 的两个一百万。
    Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
    面试官都震惊,你这网络基础可以啊!
    你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
    心情不好的时候,用 Python 画棵樱花树送给自己吧
    通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
    13 万字 C 语言从入门到精通保姆级教程2021 年版
    10行代码集2000张美女图,Python爬虫120例,再上征途
小工具 小游戏
Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1

京公网安备 11010502049817号