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.mzph.cn/news/200166.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

HashMap相关专题

前置知识&#xff1a;异或运算 异或运算介绍 异或有什么神奇之处&#xff08;应用&#xff09;&#xff1f; &#xff08;1&#xff09;快速比较两个值 &#xff08;2&#xff09;我们可以使用异或来使某些特定的位翻转&#xff0c;因为不管是0或者是1与1做异或将得到原值的相…

IntelliJ IDEA 2023.2新特性详解第三弹!Docker、Kubernetes等支持!

9 Docker 在 Docker 镜像层内预览文件 现在可以在 Services&#xff08;服务&#xff09;工具窗口中轻松访问和预览 Docker 镜像层的内容。 从列表选择镜像&#xff0c;选择 Show layers&#xff08;显示层&#xff09;&#xff0c;然后点击 Analyze image for more informati…

<软考>软件设计师-2操作系统(总结)

(一) 进程管理 1 操作系统概述 1-1 操作系统定义: 能有效地组织和管理系统中的各种软/硬件资源&#xff0c;合理地组织计算机系统工作流程&#xff0c;控制程序的执行&#xff0c;并且向用户提供一个良好的工作环境和友好的接口。 1-2 操作系统的作用: 1 通过资源管理提高计…

7+WGCNA+机器学习+实验+泛癌分析,多要素干湿结合

今天给同学们分享一篇生信文章“Analysis and Experimental Validation of Rheumatoid Arthritis Innate Immunity Gene CYFIP2 and Pan-Cancer”&#xff0c;这篇文章发表在Front Immunol期刊上&#xff0c;影响因子为7.3。 结果解读&#xff1a; DEG筛选和数据预处理 数据在…

Helplook VS Google Docs:一对一比较

还记得Google Docs在2006年一炮走红的时候吗&#xff1f;它很大程度地改变了协作方式&#xff0c;也减少了附加文件和频繁保存的麻烦。相比Microsoft Word&#xff0c;很多人更喜欢Google Docs的简单性。 但是时代也在不断地发展。像HelpLook这样的新竞争对手也可以提供先进的…

字符集——带你了解UTF-8的前世今生

文章目录 字符集的来历汉字和字母的编码特点Unicode字符集字符集小结编码和解码开发约定 字符集的来历 计算机是美国人发明的&#xff0c;由于计算机能够处理的数据只能是0和1组成的二进制数据&#xff0c;为了让计算机能够处理字符&#xff0c;于是美国人就把他们会用到的每一…

前端面试高频考点—事件循环Event loop

目录 事件循环 执行步骤 概念讲解 主线程 微任务(micro task) 宏任务(macro task) Event Loop经典例题 这段代码的执行结果是什么&#xff1f; 正确答案&#xff1a; 具体流程&#xff1a; 事件循环 主线程从"任务队列"中读取执行事件&#xff0c;这个过程…

File类—递归文件搜索执行脚本文件

文章目录 一、需求分析二、File类2.1 File对象的创建2.2 File判断和获取方法2.3 创建和删除方法2.4 遍历文件夹方法 三、Runtime类—常见api四、递归文件搜索执行脚本文件 一、需求分析 在本篇博客中&#xff0c;我们想通过递归文件的方式&#xff0c;在D:\\判断下搜索QQ.exe这…

麒麟V10安装kerberos客户端

麒麟V10系统安装kerberos客户端 当系统具备yum镜像源的时候需要执行安装命令 yum install krb5-devel krb5-client krb5-libs -y 会提示报错 “未找到匹配的参数:krb5-client” 此时我们需要手动安装krb5-client 安装包链接放到了这里 链接: https://pan.baidu.com/s/1x1YVr6…

SQL Server的安装和首个库的创建

一、熟悉SQL Server的安装环境&#xff1b; 1.安装Microsoft的数据库管理系统SQL Server 2022 先把SQL Server 2022下载好后进行解压后出现以下界面然后点击基本进行安装 然后会出现以下界面&#xff1a; 一步步按照提示往下走即可&#xff0c;把SQL Server 2022安装完成后再…

Leetcode刷题笔记题解(C++):LCR 021. 删除链表的倒数第 N 个结点

思路&#xff1a;用双指针去遍历链表&#xff0c;删除left的下一个节点&#xff0c;注意的是n大于等于链表长度即删除第一个节点 /*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {…

tmux简单使用

它允许你在一个终端窗口中创建多个终端会话&#xff0c;并在它们之间进行切换。以下是tmux的一些主要用途和功能&#xff1a; 多窗口&#xff1a; Tmux允许你在一个终端中创建多个窗口。每个窗口可以包含一个或多个终端会话&#xff0c;你可以轻松地在这些窗口之间切换。面板分…

不愧是字节出来的,太厉害了。。。

前段时间公司缺人&#xff0c;也面了许多测试&#xff0c;一开始瞄准的就是中级水准&#xff0c;当然也没指望能来大牛&#xff0c;提供的薪资在15-20k这个范围&#xff0c;来面试的人有很多&#xff0c;但是平均水平真的让人很失望。看了简历很多上面都是写有4年工作经验&…

Jmeter 接口-加密信息发送(一百九十九)

方式1&#xff1a;使用函数助手 比如MD5加密方式&#xff1a; 如图&#xff0c;需要对${user}进行MD5加密 1、打开函数助手&#xff0c;找到MD5&#xff0c;输入需要加密的值 2、将${__MD5(${user},)}放到请求中 3、查看请求&#xff0c;请求成功 方式2&#xff1a;导入jar包…

Docker实战【镜像部署】

文章目录 &#x1f4a5; 简介&#x1f4a1; 基础-Tomcat镜像部署&#x1f396;️ 企业实战-制作Tomcat项目镜像&#x1f3af; 企业实战-Docker部署SpringBoot项目&#x1f680; 问题复盘&#x1f353; 总结 &#x1f4a5; 简介 由于公司内部机器要做迁移&#xff0c;原系统机器…

深度学习优化器

不断优化 Example:for input, target in dataset:optimizer.zero_grad()output model(input)loss loss_fn(output, target)loss.backward()optimizer.step() import torch import torchvision.datasets from torch import nn from torch.nn import Sequential,Conv2d,MaxPoo…

题目:小明的彩灯(蓝桥OJ 1276)

题目描述&#xff1a; 解题思路&#xff1a; 一段连续区间加减&#xff0c;采用差分。最终每个元素结果与0比较大小&#xff0c;比0小即负数输出0。 题解&#xff1a; #include<bits/stdc.h> using namespace std;using ll long long; const int N 1e5 10; ll a[N],…

跨语种「AI同传」颠覆语音翻译!Meta谷歌连发重大突破

Meta谷歌接连放出重磅成果&#xff01;Meta开源无缝交流语音翻译模型&#xff0c;谷歌放出无监督语音翻译重大突破Translation 3。 就在Meta AI成立10周年之际&#xff0c;研究团队重磅开源了在语音翻译领域的突破性进展——「无缝交流」&#xff08;Seamless Communication&a…

Spring Cloud NetFlix

文章目录 Spring Cloud NetFlix1 介绍2 Eureka&#xff08;服务注册与发现&#xff09;2.1 介绍2.2 服务注册与发现示例2.2.1 Eureka Server&#xff1a;springcloud-eureka2.2.2 Eureka Client&#xff1a;springcloud-provider2.2.3 Eureka Client&#xff1a;springcloud-co…

激光炸弹(二维前缀和)-Java版

import java.io.*;/** 题目分析:一个最大5000 * 5000 的矩阵, 爆炸范围在 [0,10e9]* 地图上的目标是随机分布,如果要暴力计算每一个区间R的权值,会很麻烦* 可以用二维前缀和先将权值存起来* for(int i 1;i < n;i ) {for(int j 1;j < m;j ) {g[i][j] g[i][j-1] g[i-1]…