力扣每日一题115:不同的子序列

embedded/2024/10/18 18:28:08/

题目

困难

给你两个字符串 s 和 t ,统计并返回在 s 的 子序列 中 t 出现的个数,结果需要对 109 + 7 取模。

示例 1:

输入:s = "rabbbit", t = "rabbit"
输出3
解释:
如下所示, 有 3 种可以从 s 中得到 "rabbit" 的方案rabbbit
rabbbit
rabbbit

示例 2:

输入:s = "babgbag", t = "bag"
输出5
解释:
如下所示, 有 5 种可以从 s 中得到 "bag" 的方案babgbag
babgbag
babgbag
babgbag
babgbag

提示:

  • 1 <= s.length, t.length <= 1000
  • s 和 t 由英文字母组成

面试中遇到过这道题?

1/5

通过次数

177K

提交次数

340.8K

通过率

51.9%

思路

注意!这是一道hard题!

看到xxx序列在xxx序列中xxx的个数、序列的最长xxx子序列、最长xxx串,最短xxx串这些题目,一眼就想到动态规划。

序列t在序列s的子序列中出现的次数,出现了两个序列的匹配,毫无疑问是二维dp,我们采用由前向后dp的思路,dp[i][j]来表示 t[1:i] 在 s[1:j] 的子序列中出现的次数。注意!由于动态规划一般要对边界值进行讨论,dp的下标从[1][1]开始,[0][……]和[……][0]用来做边界值的讨论。

对于这种两个字符串的动态规划,一般都是讨论 [i] 和 [j] 各自对应的字符是否相等来分类。

状态转移

1、如果t[i-1]!=s[j-1],也就是 i 对应的字符和 j 对应的字符不相等的情况。

要实现 t[1:i] 和 s[1:j] 的匹配,因为两部分切片的最后一个字符不相等,所有只能祈求 t[1:i] 能不能和 s[1:j-1]  能不能匹配。\thereforedp[i][j]=dp[i][j-1]。

2、t[i-1]==s[j-1]

两部分切片的最后一个字符相等,所以我们既可以选择两种匹配方法

a、t[i-1] 和 s[j-1] 匹配完成后,t[1:i-1]和t[1:j-1]匹配,这一部分的方案数量是 dp[i-1][j-1]

b、t[i-1]不和s[j-1]匹配,这时就和t[i-1]!=s[j-1]一样,这一部分方案数量就是 dp[i][j-1]

\therefore dp[i][j]=dp[i-1][j-1]+dp[i][j-1]

边界情况的讨论。

状态转移方程中,我们要用到dp[i-1][j-1],而我们的状态转移的循环是

        for(int i=1;i<=m;i++){for(int j=i;j<=n;j++){if(t[i-1]!=s[j-1]){dp[i][j]=dp[i][j-1];}else{//t[i-1]和s[j-1]匹配+t[i-1]不和s[j-1]匹配dp[i][j]=dp[i-1][j-1]+dp[i][j-1];}}}

m是t串的长度,n是s串的长度。

从循环上看,j<i||i==0 这一部分是没有出现在循环里的,但是i-1和j-1能遍历到,所以我们必然要讨论。

i=0时,代表切片为空串,空串是任何串的子串,所以这一部分的初值为1。

j<i时,s串长度小于t串,这是不可能是子串,所以这一部分初值为0。

        vector<vector<unsigned long long>> dp(m+1,vector<unsigned long long>(n+1,0));//边界情况-->空字符串是任何字符串的子序列for(int i=0;i<=n;i++){dp[0][i]=1;}

代码(注意数据范围和取模)

class Solution {
public:const int mod=1e9+7;int numDistinct(string s, string t) {int n=s.length();int m=t.length();if(n<m) return 0;//dp[i][j]-->t[1-i]在s[1-j]中出现的次数()//防止边界条件判断,从[1][1]开始算//long long都会超出数据范围vector<vector<unsigned long long>> dp(m+1,vector<unsigned long long>(n+1,0));//边界情况-->空字符串是任何字符串的子序列for(int i=0;i<=n;i++){dp[0][i]=1;}for(int i=1;i<=m;i++){for(int j=i;j<=n;j++){if(t[i-1]!=s[j-1]){dp[i][j]=dp[i][j-1];}else{//t[i-1]和s[j-1]匹配+t[i-1]不和s[j-1]匹配dp[i][j]=dp[i-1][j-1]+dp[i][j-1];}}}int ans=dp[m][n]%mod;return ans;}
};


http://www.ppmy.cn/embedded/39849.html

相关文章

java设计模式 桥接

桥接模式&#xff08;Bridge Pattern&#xff09;是软件工程中的一种设计模式&#xff0c;它将抽象部分与它的实现部分分离&#xff0c;使它们可以独立变化。这种类型的设计模式属于结构型模式&#xff0c;它通过提供抽象化和实现化之间的桥接结构&#xff0c;来实现二者的解耦…

动手学深度学习16 Pytorch神经网络基础

动手学深度学习16 Pytorch神经网络基础 1. 模型构造2. 参数管理1. state_dict()2. normal_() zeros_()3. xavier初始化共享参数的好处 3. 自定义层4. 读写文件net.eval() 评估模式 QA 1. 模型构造 定义隐藏层–模型结构定义前向函数–模型结构的调用 import torch from torch…

HTML【常用的标签】、CSS【选择器】

day45 HTML 继day44&#xff0c;w3cschool 常用的标签 k) 表格 表格由 table 标签来定义。每个表格均有若干行&#xff08;由 tr 标签定义&#xff09;&#xff0c;每行被分割为若干单元格&#xff08;由 标签定义&#xff09;。字母 td指表格数据&#xff08;table data&…

推荐全网最全的AI小白进阶指南

1. 引言 您想学习人工智能&#xff1f;但不知道如何开始&#xff0c;也不知道从哪里开始&#xff1f;互联网上的资源总是丰富多彩&#xff0c;质量参差不齐&#xff0c;往往容易看花眼而无从下手。 鉴于此&#xff0c;本文重点推荐一些个人收集的还不错的一些资源供大家学习参…

网络安全专业岗位详解+自学学习路线图

很多网安专业同学一到毕业就开始迷茫&#xff0c;不知道自己能去做哪些行业&#xff1f;其实网络安全岗位还是蛮多的&#xff0c;下面我会介绍一些网络安全岗位&#xff0c;大家可以根据自身能力与喜好决定放哪个方向发展。 渗透测试/Web安全工程师 主要是模拟黑客攻击&#…

gpt_academic的使用——含一键安装和接入其他API以及本地模型

https://github.com/binary-husky/gpt_academic/releases/ https://github.com/binary-husky/gpt_academic/wiki 安装

2016-2021年全国范围的2.5m分辨率的建筑屋顶数据

一、论文介绍 摘要&#xff1a;大规模且多年的建筑屋顶面积&#xff08;BRA&#xff09;地图对于解决政策决策和可持续发展至关重要。此外&#xff0c;作为人类活动的细粒度指标&#xff0c;BRA可以为城市规划和能源模型提供帮助&#xff0c;为人类福祉带来好处。然而&#xf…

微服务架构中的挑战及应对方式:Outbox 模式

使用 Outbox 模式保持微服务数据一致性 在一个由许多小型服务组成的系统中保持数据一致性是困难的&#xff0c;因为它们分散在各处。以下是一些常见问题以及如何处理它们的方法&#xff1a;当服务发送消息时&#xff0c;同时更新数据库和发送消息是棘手的问题。 在微服务中发出…