C++ day55 判断子序列 不同的子序列

题目1:392 判断子序列

题目链接:判断子序列

对题目的理解

判断字符串s是否为t的子序列

字符串s和字符串t的长度大于等于0,字符串s的长度小于等于字符串t的长度,本题其实和最长公共子序列的那道题很相似,相当于找两个子序列的最长公共序列长度,最终这个最长公共序列的长度是否等于字符串s的长度

进阶:如果有大量的字符串s,s1,s2,....,sk(k>=10亿),依次检查是否为t的子序列

动态规划(编辑距离的入门题目)

动规五部曲

1)dp数组及下标i的含义

dp[i][j]:以i-1为结尾的字符串s和以j-1为结尾的字符串t的最长公共子序列的长度

2)递推公式

if (s[i - 1] != t[j - 1]),此时相当于t要删除元素,如果把当前元素t[j - 1]删除,那么dp[i][j] 的数值就是 看s[i - 1]与 t[j - 2]的比较结果了,即:dp[i][j] = dp[i][j - 1];

3)dp数组初始化

根据dp数组的定义,dp[i][0],dp[0][j]没有意义,但是为了满足递推公式,将其初始化为0,其余下标初始化为任意值均可,在之后的计算会被新值覆盖,但是为了初始化方便,均初始成0

4)遍历顺序

根据递推公式,dp[i][j]由dp[i-1][j-1]和dp[i][j-1]推出,遍历顺序从上到下,从左到右

5)打印dp数组

最终的输出结果是dp[s.size()][t.size()]代表最长相同子序列的长度,因为一定要将字符串s和字符串t遍历完,才能判断字符串是否为字符串s的子序列,要不放过任何一个字符,这样才能确保完整性,不落掉任意一个字符,如果这个长度等于s.size(),说明s是t的子序列,返回true

代码,可以直接使用最长公共子序列的代码,只是在最终返回结果的时候与s.size()比较一下

class Solution {
public:
    bool isSubsequence(string s, string t) {
        //定义并初始化dp数组
        vector<vector<int>> dp(s.size()+1,vector<int>(t.size()+1,0));
        for(int i=1;i<=s.size();i++){
            for(int j=1;j<=t.size();j++){
                if(s[i-1]==t[j-1]) dp[i][j]=dp[i-1][j-1]+1;
                else dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
            }
        }
        if(dp[s.size()][t.size()]==s.size()) return true;
        else return false;
    }
};

代码2,是动规五部曲中递推公式中的那个,因为s是最长公共子序列子序列,所以只在t字符串中考虑是否删除元素从而达到减少字符而和字符串s匹配的目的

class Solution {
public:
    bool isSubsequence(string s, string t) {
        //定义并初始化dp数组
        vector<vector<int>> dp(s.size()+1,vector<int>(t.size()+1,0));
        int result = 0;
        for(int i=1;i<=s.size();i++){
            for(int j=1;j<=t.size();j++){
                if(s[i-1]==t[j-1]) dp[i][j]=dp[i-1][j-1]+1;
                else dp[i][j]=dp[i][j-1];
                result = max(result,dp[i][j]);
            }
        }
        if(result==s.size()) return true;
        else return false;
    }
};
  • 时间复杂度:O(n × m)
  • 空间复杂度:O(n × m)

代码也可以这样

class Solution {
public:
    bool isSubsequence(string s, string t) {
        //定义并初始化dp数组
        vector<vector<int>> dp(s.size()+1,vector<int>(t.size()+1,0));
        for(int i=1;i<=s.size();i++){
            for(int j=1;j<=t.size();j++){
                if(s[i-1]==t[j-1]) dp[i][j]=dp[i-1][j-1]+1;
                else dp[i][j]=dp[i][j-1];
            }
        }
        if(dp[s.size()][t.size()]==s.size()) return true;
        else return false;
    }
};

题目2:115 不同的子序列

题目链接:不同的子序列

对题目的理解

返回字符串t在字符串s的子序列中出现的个数   注意说的是s的子序列,不一定连续

题目保证答案符合 32 位带符号整数范围

动态规划

动规五部曲

1)dp数组及下标i的含义

dp[i][j] :以i-1为结尾的字符串s中有以j-1为结尾的字符串t个数

2)递推公式

这一类问题,基本是要分析两种情况

  • 当前两字符串末尾的字母相等,s[i - 1] 与 t[j - 1]相等
  • 当前两字符串末尾的字母不等,s[i - 1] 与 t[j - 1] 不相等

s[i - 1] 与 t[j - 1]相等,dp[i][j]可以有两部分组成,(因为字符串s中,可能会包括相同字母顺序出现多次的情况)

1)使用当前的s[i - 1]匹配t[j-1],因为这两个字母已经相同了,所以不需要考虑当前s子串和t子串的最后一位字母s[i-1]和t[j-1]了,即只需要根据前面的s[i-2]和t[j-2]计算的dp[i-1][j-1]个数继续赋值就行,就看前面计算了多少个就可以了,这个继续向下进行赋值就OK

2)不使用当前的s[i - 1]来匹配t[j-1]

例如: s:bagg 和 t:bag ,s[2],s[3] 和 t[2]是相同的,可以用s[3]来匹配,也可以用s[2]匹配,

当s[3]和t[2]相匹配时,当前的s[i-1]与t[i-1]相匹配都对应着最后一个字母g,此时就是第一种情况,取决于dp[i-1][j-1];

但是不使用s[3](假设删除了元素s[3],也有可能和t相匹配),而是使用s[2]来匹配t[2]也是可以的,字符串t中要匹配的字母t[2]还是不变,只是s子串的最后一个字母发生了变化(由s[3]处的g变为s[2]处的g)而已,个数就为同样的t[j]在前面s[i-2]计算的个数,即对应着dp数组中的dp[i-1][j],

所以当s[i - 1] 与 t[j - 1]相等时,将这两种情况得到的结果进行相加,dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];

当s[i - 1] 与 t[j - 1]不相等时,dp[i][j]只有一部分组成

因为两个子串最末尾的字符已经不等了,所以无法使用s[i-1]匹配t[j-1],则对于t[j-1]不考虑s[i-1],模拟将字符串中的s[i-1]这个元素删除,那么就拿上一层,也就是字符s[i-1]的前一个字符s[i-2]来匹配字符t[i-1]的结果来作为当前字符s[i-1]匹配t[j-1]的结果,

dp[i][j] = dp[i - 1][j]

3)dp数组初始化

根据递推公式,dp[i][j]是从上方和左上方推导而来,第一行与第一列要进行初始化,是递推公式的基础。

根据dp数组定义,dp[i][0]   代表以i-1为结尾的字符串s中有以-1为结尾的空字符串t的个数,而s不为空,如果将s中的字符都删除,则会变成空字符串t  ,则有一个

dp[0][j]  代表以-1为结尾的字符串s中有以j-1为结尾的t字符串的个数,此时s是空字符串,而t不是空字符串,所以无论怎么改变s,都没有办法组成t字符串,所以有0个

交集  dp[0][0] = 1 :空字符串s中有1个空i字符串t

4)遍历顺序

根据递推公式  从左到右,从上到下

5)打印dp数组

最终的结果是dp[s.size()][t.size()],因为最终一定要将字符串s和字符串t遍历完,才能最终判定字符串s中有多少个字符串t,这样才能不落掉任何一个字符,保证字符全部都遍历到,这样才能不落掉任何一个个数

代码

class Solution {
public:
    int numDistinct(string s, string t) {
        //定义并初始化dp数组
        vector<vector<int>> dp(s.size()+1,vector<int>(t.size()+1,0));
        //初始化dp数组
        for(int i=0;i<s.size();i++) dp[i][0]=1;
        for(int i=1;i<=s.size();i++){
            for(int j=1;j<=t.size();j++){
                if(s[i-1]==t[j-1]) dp[i][j]=dp[i-1][j-1]+dp[i-1][j];
                else dp[i][j]=dp[i-1][j];
            }
        }
        return dp[s.size()][t.size()];
    }
};

上述代码会报如下错误

会有溢出错误,因为是两个整数相加,结果超出了int类型的表示范围

将代码改为如下

class Solution {
public:
    int numDistinct(string s, string t) {
        //定义并初始化dp数组
        vector<vector<uint64_t>> dp(s.size()+1,vector<uint64_t>(t.size()+1,0));
        //初始化dp数组
        for(int i=0;i<s.size();i++) dp[i][0]=1;
        for(int i=1;i<=s.size();i++){
            for(int j=1;j<=t.size();j++){
                if(s[i-1]==t[j-1]) dp[i][j]=dp[i-1][j-1]+dp[i-1][j];
                else dp[i][j]=dp[i-1][j];
            }
        }
        return dp[s.size()][t.size()];
    }
};
  • 时间复杂度: O(n * m)
  • 空间复杂度: O(n * m)

也可以将类型改为unsigned long long也能顺利通过,代码如下

class Solution {
public:
    int numDistinct(string s, string t) {
        //定义并初始化dp数组
        vector<vector<unsigned long long>> dp(s.size()+1,vector<unsigned long long>(t.size()+1,0));
        //初始化dp数组
        for(int i=0;i<s.size();i++) dp[i][0]=1;
        for(int i=1;i<=s.size();i++){
            for(int j=1;j<=t.size();j++){
                if(s[i-1]==t[j-1]) dp[i][j]=dp[i-1][j-1]+dp[i-1][j];
                else dp[i][j]=dp[i-1][j];
            }
        }
        return dp[s.size()][t.size()];
    }
};

流程

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/221070.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

gitlab高级功能之容器镜像仓库

今天给大家介绍一个gitlab的高级功能 - Container Registry&#xff0c;该功能可以实现docker镜像的仓库功能&#xff0c;将gitlab上的代码仓的代码通过docker构建后并推入到容器仓库中&#xff0c;好处就是无需再额外部署一套docker仓库。 文章目录 1. 参考文档2. Container R…

yolov8添加ca注意力机制

创建文件 coordAtt.py 位置&#xff1a;ultralytics/nn/modules/coordAtt.py ###################### CoordAtt #### start by AI&CV ############################### # https://zhuanlan.zhihu.com/p/655475515 import torch import torch.nn as nn import t…

在Windows11(WSL)中如何迁移Docker

前言&#xff1a; 在Windows 10中Docker是默认安装到WSL中的&#xff0c;而安装到WSL中的任意分发版都是默认放在C盘中的。这样会让我们的C盘资源极度紧张&#xff0c;而且也限制了Docker的镜像数量。 迁移步骤 假设我有一个临时目录“D:\docker”用来存放临时文件&#xff0c;…

【开源】基于Vue和SpringBoot的在线课程教学系统

项目编号&#xff1a; S 014 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S014&#xff0c;文末获取源码。} 项目编号&#xff1a;S014&#xff0c;文末获取源码。 目录 一、摘要1.1 系统介绍1.2 项目录屏 二、研究内容2.1 课程类型管理模块2.2 课程管理模块2…

黑马头条数据管理平台项目总结

今天主要看了该项目的介绍&#xff0c;这个黑马头条数据管理平台项目主要包括登录、用户的权限判断、文章内容列表的筛选和分页、文章的增删查改还有图片和富文本编辑器这几大部分组成&#xff0c;项目配套了素材代码&#xff0c;像资源文件、第三方插件、页面文件夹、工具插件…

【MySQL】表的增删查改

增创建库创建表表插入表更新插入表替换插入查询结果 查全列查找指定列查找查找结果去重where条件查找筛选分页结果 改对查询到的结果进行列值更新 删delete 和 truncate 的区别 增 创建库创建表 create database 库名称;use 进入的库名称;create table 表名称; select * from…

Apollo新版本Beta技术沙龙

有幸参加Apollo开发者社区于12月2日举办的Apollo新版本(8.0)的技术沙龙会&#xff0c;地址在首钢园百度Apollo Park。由于去的比较早&#xff0c;先参观了一下这面的一些产品&#xff0c;还有专门的讲解&#xff0c;主要讲了一下百度无人驾驶的发展历程和历代产品。我对下面几个…

单点登录方案调研与实现

作用 在一个系统登录后&#xff0c;其他系统也能共享该登录状态&#xff0c;无需重新登录。 演进 cookie → session → token →单点登录 Cookie 可以实现浏览器和服务器状态的记录&#xff0c;但Cookie会出现存储体积过大和可以在前后端修改的问题 Session 为了解决Co…

Doris 集成 ElasticSearch

Doris-On-ES将Doris的分布式查询规划能力和ES(Elasticsearch)的全文检索能力相结合,提供更完善的OLAP分析场景解决方案: (1)ES中的多index分布式Join查询 (2)Doris和ES中的表联合查询,更复杂的全文检索过滤 1 原理 (1)创建ES外表后,FE会请求建表指定的主机,获取所有…

Git 应用 -- 多人协作开发场景1

目录 1. 既查看本地仓库的分支&#xff0c;又查看远程仓库的分支&#xff1a; git branch -a &#xff08;但是远程的分支只能查看&#xff0c;不能直接切换到远程的分支上&#xff09; 2. 本地的分支和远程的分支建立连接&#xff1a;git checkout -b [分支名] [要连接远程的…

【模型可解释性系列一】树模型-拿到特征重要度-打印关键因素

接下来一段时间内&#xff0c;会主要介绍下模型可解释性方向的一些常用方法。 模型可解释性&#xff1a;主要用来解释为什么这个样本的特征是这样的时候&#xff0c;模型结果是那样。面向老板汇报工作(尤其是不懂算法的老板)和业务方。 常用的树模型 xgboost、lightgbm这两个…

Ps:文字操作常用快捷键

对文字的设置操作&#xff0c;可在工具选项栏或“字符”面板上进行。但是&#xff0c;如果能记住并使用快捷键&#xff0c;可大大提高工作效率。 设置文字颜色 Color 1、选中几个或全部文字后&#xff0c;除了使用工具选项栏上的“颜色”按钮&#xff0c;还可以使用快捷键 Alt…

Linux系统调试课:PCIe调试手段

文章目录 一、lspci 命令二、pciutils 工具沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本文我们要介绍pcie调试手段。 一、lspci 命令 通过lspci可以查看当前系统挂载了哪些pci设备。 lspci - 列出 PCI 设备 lspci 命令可以列出计算机中所有 PCI 设备的详细信息,…

23、pytest通过skip跳过测试用例

官方实例 # content of test_skip.py import pytest import syspytest.mark.skip(reason"no way of currently testing this") def test_the_unknown():passdef valid_config():return Falsedef test_function():if not valid_config():pytest.skip("unsupport…

Android View.inflate 和 LayoutInflater.from(this).inflate的区别

前言 两个都是布局加载器&#xff0c;而View.inflate是对 LayoutInflater.from(context).inflate的封装&#xff0c;功能相同&#xff0c;案例使用了dataBinding。 View.inflate(context, layoutResId, root) LayoutInflater.from(context).inflate(layoutResId, root, fals…

如何通过navicat连接SQL Server数据库

本文介绍如何通过Navicat 连接SQL Server数据库。如果想了解如何连接Oracle数据库&#xff0c;可以参考下边这篇文章。如何通过Navicat连接Oracle数据库https://sgknight.blog.csdn.net/article/details/132064235 1、新建SQL Server连接配置 打开Navicat软件&#xff0c;点击…

centos7安装Elasticsearch7系列

背景 今天公司项目需要使用Elasticsearch7.17.7。所有网上搜索了一番&#xff0c;查到一个很不错安装方式分享给大家。 Elasticsearch官网发布 从 Elasticsearch 7.x 版本开始&#xff0c;Elasticsearch 发行版包括了自己的 JDK。因此&#xff0c;您不需要单独安装 Java。以…

2023.2版idea安装教程,现在jdk8已经过去式了,不同idea支持的jdk不同。升级jdk后idea也要随之升级

下载idea2023.2版本&#xff0c;下载之前需要删除之前的版本&#xff0c;一定要删除干净&#xff0c;删除程序要勾选那两个delete 下载路径&#xff1a;其他版本 - IntelliJ IDEA (jetbrains.com.cn) 选择2023.2版本 下载后进入安装程序&#xff0c;选择安装目录&#xff0c;然…

去掉参数中第一个“,”

记录一下&#xff0c;前端传参中&#xff0c;传给我参数是“categoryIds: ,1731557494586241026,1731569816263311362,1731569855534579713,1731858335179223042,1731858366821052418” 但是后端&#xff0c;因为我的mybati是in查询&#xff0c;所以因为第一个是“,”。所以会导…

提升设备巡检效率的有效工具

易点易动设备管理系统是一款专注于提升设备巡检效率的高效工具。设备巡检是企业设备管理的重要环节&#xff0c;通过定期巡检设备&#xff0c;可以及时发现潜在问题&#xff0c;预防故障发生&#xff0c;确保设备安全运行。下面将介绍易点易动设备管理系统在设备巡检方面的功能…
最新文章