leetcode
leetcode 3051 ~ 3100
不同的子序列

不同的子序列

难度:

标签:

题目描述

English description is not available for the problem. Please switch to Chinese.

代码结果

运行时间: 31 ms, 内存: 16.5 MB


解释

方法:

这个题解使用了动态规划的方法来解决问题。定义dp数组,其中dp[i][j]表示字符串s的前i个字符中t的前j个字符作为子序列出现的个数。首先,初始化dp[0][0]为1,表示空字符串s可以匹配空字符串t的方式为1种。对于所有i,dp[i][0]也都设置为1,因为空字符串t是任意字符串s的子序列。接着,我们遍历字符串s和t的每个字符,如果s[i]和t[j]相同,那么dp[i+1][j+1]的值应该是dp[i][j](s[i]参与匹配)加上dp[i][j+1](s[i]不参与匹配)的总和。如果s[i]和t[j]不同,那么dp[i+1][j+1]的值仅为dp[i][j+1]。最后,dp[len(s)][len(t)]的值就是答案。

时间复杂度:

O(n*m)

空间复杂度:

O(n*m)

代码细节讲解

🦆
如何理解动态规划数组dp[i][j]的含义,即它代表了什么?
动态规划数组dp[i][j]表示字符串s的前i个字符中包含字符串t的前j个字符作为子序列的不同方式的个数。具体地,dp[i][j]计数了所有可能的从s的前i个字符中选择出t的前j个字符的序列组合,而不改变t中字符的顺序的方式。
🦆
初始化dp[i][0]为1是基于什么考虑?空字符串t为什么是任意字符串s的子序列?
初始化dp[i][0]为1是基于这样一个事实:空字符串可以作为任何字符串的子序列,而且仅有一种方式来实现这一点,即不从字符串s中选择任何字符。因此,对于任意长度的s,总有一种方法将空字符串t作为s的子序列,这就是什么也不选择的情况。
🦆
为什么在s[i]和t[j]字符相同的情况下,dp[i+1][j+1]的值是dp[i][j]和dp[i][j+1]的和?这种更新策略背后的逻辑是什么?
当s[i]和t[j]字符相同的时候,我们有两种选择:一是利用这个相同的字符来匹配t中的字符,二是不利用这个相同的字符。如果我们选择利用s[i]来匹配t[j],那么剩下的任务就是从s的前i个字符中匹配t的前j个字符,这对应的情况数为dp[i][j]。如果我们选择不利用s[i]来匹配t[j],即使它们相同,那么问题就变成了从s的前i个字符匹配t的前j+1个字符,这对应的情况数为dp[i][j+1]。因此,dp[i+1][j+1]的值应该是这两种选择的总和。

相关问题