-
392判断子序列
- 代码随想录 (programmercarl.com)
-
第一印象
- 这题可以直接使用 最长公共子序列的方法。当得到的最长值达到子序列的长度,则代表满足子序列关系。
- 也可以使用指针的方法。使用idx记录t的位置直接搜索相同的字符,如果能够满足搜索到s串最后,则成立。
-
讲解观后感
- 依旧是按照动态规划的固定解题路线。首先,dp[i][j] 表示以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,相同子序列的长度为dp[i][j]。
- 然后确定确定递推公式
if (s[i - 1] == t[j - 1]),那么dp[i][j] = dp[i - 1][j - 1] + 1
if (s[i - 1] != t[j - 1]),那么dp[i][j] 的数值就是 看s[i - 1]与 t[j - 2]的比较结果了,即:dp[i][j] = dp[i][j - 1] - dp数组如何初始化:
- 在定义dp[i][j]含义的时候为什么要表示以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,相同子序列的长度为dp[i][j]。
- 因为这样的定义在dp二维矩阵中可以留出初始化的区间,如图:
- 根据上图也可以看出,我们的遍历方向应该是从前到后,从上到小
-
解题代码
- 动态规划
-
func isSubsequence(s string, t string) bool { dp := make([][]int,len(s)+1) for i:=0;i<len(dp);i++{ dp[i] = make([]int,len(t)+1) } for i:=1;i<len(dp);i++{ for j:=1;j<len(dp[i]);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] } } } return dp[len(s)][len(t)]==len(s) - 指针
-
func isSubsequence(s string, t string) bool { idx := 0 i:=0 j:=0 for i<len(s) && j<len(t) { for j=idx;j<len(t);j++ { if s[i] == t[j] { i++ idx = j+1 break } } } return i == len(s) } -
115不同的子序列
- 代码随想录 (programmercarl.com)
-
讲解观后感
- 我们还是按照动态规划的固定解题顺序来解决。首先确定dp数组(dp table)以及下标的含义
dp[i][j]:以i-1为结尾的s子序列中出现以j-1为结尾的t的个数为dp[i][j]。这样定义的原因是为了方便的初始化。 - 在确定递推公式上本题较难理解。首先我们可以确定情况只有两种:
- s[i - 1] 与 t[j - 1]相等
- s[i - 1] 与 t[j - 1] 不相等
- 我们先讨论相等的情况。相等时可以由两种状态推导而来。一种是用s[i - 1]来匹配,那么个数为
dp[i - 1][j - 1]。代表着包含s[i-1]和t[j-1]这两个字符的相同子序列的数量。
另一种是不用s[i - 1]来匹配,个数为dp[i - 1][j]。代表着在s[i-1]之前任意位置能够匹配t[j-1]的子序列的数量 - 然后我们来看不相等的情况。不相等时,dp[i][j]只有一部分组成,不用s[i - 1]来匹配(就是模拟在s中删除这个元素),即:dp[i - 1][j]
- dp数组如何初始化:从递推公式dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j]; 和 dp[i][j] = dp[i - 1][j]; 中可以看出dp[i][j] 是从上方和左上方推导而来,,那么 dp[i][0] 和dp[0][j]是一定要初始化的。
- dp[i][0] 表示:以i-1为结尾的s可以随便删除元素,出现空字符串的个数。那么dp[i][0]一定都是1。
- dp[0][j]:空字符串s可以随便删除元素,出现以j-1为结尾的字符串t的个数。那么dp[0][j]一定都是0。
- 注意dp[0][0]应该为1,因为空字符串s,可以删除0个元素,变成空字符串t。
-
解题代码
-
func numDistinct(s string, t string) int { dp:= make([][]int,len(s)+1) for i:=0;i<len(dp);i++{ dp[i] = make([]int,len(t)+1) } // 初始化 for i:=0;i<len(dp);i++{ dp[i][0] = 1 } // dp[0][j] 为 0,默认值,因此不需要初始化 for i:=1;i<len(dp);i++{ for j:=1;j<len(dp[i]);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[len(s)][len(t)] }