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

news2024/11/26 8:40:39

题目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.coloradmin.cn/o/1287398.html

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

相关文章

面试就是这么简单,offer拿到手软(四)—— 常见java152道基础面试题

面试就是这么简单&#xff0c;offer拿到手软&#xff08;一&#xff09;—— 常见非技术问题回答思路 面试就是这么简单&#xff0c;offer拿到手软&#xff08;二&#xff09;—— 常见65道非技术面试问题 面试就是这么简单&#xff0c;offer拿到手软&#xff08;三&#xff…

【数据结构(七)】查找算法

文章目录 查找算法介绍1. 线性查找算法2. 二分查找算法2.1. 思路分析2.2. 代码实现2.3. 功能拓展 3. 插值查找算法3.1. 前言3.2. 相关概念3.3. 实例应用 4. 斐波那契(黄金分割法)查找算法4.1. 斐波那契(黄金分割法)原理4.2. 实例应用 查找算法介绍 在 java 中&#xff0c;我们…

【Midjourney实战】| 新年礼盒元素设计

文章目录 1 初步提示词2 润色提示词3 提示词发散联想 这期实践任务&#xff0c;我们想去做一个新年礼盒的效果&#xff0c;最后我们想把不同元素拼在一起&#xff0c;方便后期进行新年的相关设计 1 初步提示词 提示词初步我们乍一想&#xff0c;肯定要包括主体元素礼盒 新年礼…

APOLLO自动驾驶技术沙龙:未来已来,共创智能交通新时代

在这次Apollo会议上&#xff0c;我深刻地感受到了人工智能自动驾驶技术领域的最新进展和未来趋势。作为一名从事软件开发工作的人员&#xff0c;我深感荣幸能够参加这次盛会。 前言 本次活动是百度Apollo社区工程师齐聚首钢Park&#xff0c;带来现场实操与技术分享。主要围绕Ap…

好用的挂耳式蓝牙耳机有哪些?四款好用高性价比的耳机推荐

随着生活节奏的加快&#xff0c;挂耳式蓝牙耳机真的是越来越不可或缺了&#xff0c;不管是坐地铁、步行还是运动&#xff0c;一副好用的挂耳式蓝牙耳机都能让你感觉自己像是生活里的主角。但市面上的选择实在是太多了&#xff0c;简直让人眼花缭乱&#xff0c;不过我找了四款真…

仓库管理系统【GUI/Swing+MySQL】(Java课设)

系统类型 Swing窗口类型Mysql数据库存储数据 使用范围 适合作为Java课设&#xff01;&#xff01;&#xff01; 部署环境 jdk1.8Mysql8.0Idea或eclipsejdbc 运行效果 本系统源码地址&#xff1a; 更多系统资源库地址&#xff1a;更多Java课设系统 更多系统运行效果展示…

很全面 影响无人机自动返航的因素总结

在无人机技术不断成熟的今天&#xff0c;自主返航技术成为保障飞行安全的一种重要工具。无人机在多种情况下能够智能判断&#xff0c;主动实施返航动作&#xff0c;为用户提供更加可靠的飞行保障。以下是一些常见的无人机自动返航场景&#xff0c;让我们深入了解这项技术背后的…

玩转数据8:数据质量管理与数据清洗的实践

引言 在当今数字化时代&#xff0c;数据质量管理和数据清洗对于企业和组织来说变得至关重要。随着大数据的快速增长和数据驱动决策的普及&#xff0c;确保数据的准确性、一致性和完整性成为保证业务成功的关键因素。本文将探讨数据质量管理和数据清洗的概念、目标以及其在Java…

U-Net网络模型改进(添加通道与空间注意力机制)---亲测有效,指标提升

U-Net网络模型&#xff08;注意力改进版本&#xff09; 这一段时间做项目用到了U-Net网络模型&#xff0c;但是原始的U-Net网络还有很大的改良空间&#xff0c;在卷积下采样的过程中加入了通道注意力和空间注意力 。 常规的U-net模型如下图&#xff1a; 红色箭头为可以添加的…

电表峰谷平是怎么分时间的?

电表的峰谷平时间是指电力公司根据电力需求的不同&#xff0c;将一天的时间划分为不同的时段&#xff0c;以此来确定不同时间段内的电费价格。这种不同时段对应不同电费价格的制度&#xff0c;旨在更好地平衡电力供需&#xff0c;促进能源的高效利用。 首先&#xff0c;我们来了…

记录一下Mac配置SpringBoot开发环境

由于很多项目喜欢使用传统的 Java 8 进行开发&#xff0c;而且 Java 8 的稳定性也是经过长久考验的&#xff0c;我们接下来就尝试一下&#xff0c;在一台新的 Mac 中配置 Java 环境&#xff0c;并且开始创建 SpringBoot 项目。 首先&#xff0c;去 Oracle 官网下载 java8 JDK …

springboot详解Mybatis-Plus中分页插件PaginationInterceptor标红

1.问题描述 在springboot项目中&#xff0c;类中引用PaginationInterceptor&#xff0c;标红&#xff0c;如下图所示&#xff1a; 2.问题分析 可能是因为pom.xml中的配置原因&#xff0c;导致不支持PaginationInterceptor 3.解决问题 更换版本后 更换后&#xff0c;记得Rel…

开发的客户收到样品表示质量不如原供应商如何应对

有小伙伴问&#xff0c;在开发客户的过程当中&#xff0c;给客户寄了样品&#xff0c;客户说他的样品没有原来供应商的好怎么办&#xff1f; 这个问题我们来想一下&#xff0c;客户既然愿意把地址给我们&#xff0c;愿意去接你的样品&#xff0c;说明什么&#xff1f;说明客户…

【剑指offer|图解|位运算】训练计划VI+撞色搭配

&#x1f308;个人主页&#xff1a;聆风吟 &#x1f525;系列专栏&#xff1a;数据结构、剑指offer每日一练 &#x1f516;少年有梦不应止于心动&#xff0c;更要付诸行动。 文章目录 一. ⛳️训练计划VI&#xff08;题目难度&#xff1a;中等&#xff09;1.1 题目1.2 示例1.3 …

2024年猫罐头排行榜前十名有哪些?分享2024年猫罐头排行榜前10名

很多人家里的哈基米是不是吃猫粮吃腻了&#xff0c;或者猫猫平时不喜欢喝水&#xff0c;又或者看猫猫太瘦了想入手几款猫罐头但是又愁于不会选择。而且现在猫罐头风这么大不知道选什么好~ 作为从业5年的宠物医生&#xff0c;给你说猫罐头行业内幕。我告诫大家&#xff0c;选择…

Python网络爬虫环境的安装指南

网络爬虫是一种自动化的网页数据抓取技术&#xff0c;广泛用于数据挖掘、信息搜集和互联网研究等领域。Python作为一种强大的编程语言&#xff0c;拥有丰富的库支持网络爬虫的开发。本文将为你详细介绍如何在你的计算机上安装Python网络爬虫环境。 一、安装python开发环境 进…

SIT75179B,5V 供电, 10Mbps,全双工差分芯片/全双工 RS485/RS422 收发器

SIT75179B 是一款 4.5V~5.5V 供电全双工差分芯片&#xff0c;可完全满足 TIA/EIA-485/422 标准要求 的收发器。 SIT75179B 包括一个驱动器和一个接收器&#xff0c;两者均可独立传输信号。 SIT75179B 具有 1/8 负 载&#xff0c;允许 256 个 SIT75179B 收发器并…

【AIGC】AI作图最全提示词prompt集合(收藏级)

目录 一、正向和负向提示词 二、作图参数 你好&#xff0c;我是giszz. AI做图真是太爽了&#xff0c;解放生产力&#xff0c;发展生产力。 但是&#xff0c;你是不是也总疑惑&#xff0c;为什么别人的图&#xff0c;表现力那么丰富呢&#xff0c;而且指哪打哪&#xff0c;要…

陀螺仪防抖术语

陀螺仪防抖术语 fov 视场角 drift 零偏   MotionFusion即运动传感器的融合补偿&#xff0c;对陀螺仪、加速度计等运动测量器件的数据 进行预处理&#xff0c;通过标定和补偿&#xff0c;为防抖提供校准后的陀螺仪数据 ratio 系数 gyro 陀螺仪 calibration 校准 标定 DIS&…

深度优先搜索LeetCode979. 在二叉树中分配硬币

给你一个有 n 个结点的二叉树的根结点 root &#xff0c;其中树中每个结点 node 都对应有 node.val 枚硬币。整棵树上一共有 n 枚硬币。 在一次移动中&#xff0c;我们可以选择两个相邻的结点&#xff0c;然后将一枚硬币从其中一个结点移动到另一个结点。移动可以是从父结点到…