代码随想录算法训练营day55 | 392.判断子序列,115.不同的子序列
392.判断子序列
教程视频:https://www.bilibili.com/video/BV1tv4y1B7ym/
解法一:动态规划
思路:
1、dp[i][j]定义:以i-1结尾的s和以j-1结尾的t的相同子序列长度。
2、递推公式:
if(s.charAt(i-1)==t.charAt(j-1)){
dp[i][j]=dp[i-1][j-1]+1;
}else{
dp[i][j]=dp[i][j-1];//只要减少t的索引即可
}
3、dp数组初始化:为简化初始化流程,将dp[i][0]和dp[0][j]都初始化为0,其余下标会被覆盖
4、遍历顺序:当前状态由前一状态推导而来,外层for正序遍历s,内层for正序遍历t
5、打印验证。
class Solution {
public boolean isSubsequence(String s, String t) {
if(s==null||s.length()==0)return true;
if(t.length()<s.length())return false;
int[][] dp = new int[s.length()+1][t.length()+1];
for(int i=1;i<=s.length();i++){
for(int j=1;j<=t.length();j++){
if(s.charAt(i-1)==t.charAt(j-1)){
dp[i][j]=dp[i-1][j-1]+1;
}else{
dp[i][j]=dp[i][j-1];
}
if(dp[i][j]==s.length())return true;
}
}
return false;
}
}
解法二:双指针
class Solution {
public boolean isSubsequence(String s, String t) {
int n = s.length(), m = t.length();
int i = 0, j = 0;
while (i < n && j < m) {
if (s.charAt(i) == t.charAt(j)) {
i++;
}
j++;
}
return i == n;
}
}
115.不同的子序列
教程视频:https://www.bilibili.com/video/BV1fG4y1m75Q
解法一:动态规划
思路:
1、dp[i][j]定义:以i-1为结尾的t 在以 j-1为结尾的s 中出现的个数
2、递推公式:
if(t.charAt(i-1)==s.charAt(j-1)){
dp[i][j]=dp[i-1][j-1]+dp[i][j-1];
}else{
dp[i][j]=dp[i][j-1];
}
3、dp数组初始化:当t为空字符串时,s删除全部元素可获得t,因此dp[0][j]初始化为1,其余下标初始化为0.
4、遍历顺序:外层for正向遍历t,内层for正向遍历s
5、打印验证。
class Solution {
public int numDistinct(String s, String t) {
//s长,t短
if(t.length()>s.length())return 0;
int[][] dp = new int[t.length()+1][s.length()+1];
for(int j=0;j<=s.length();j++){
dp[0][j]=1;
}
for(int i=1;i<=t.length();i++){
for(int j=1;j<=s.length();j++){
if(t.charAt(i-1)==s.charAt(j-1)){
dp[i][j]=dp[i-1][j-1]+dp[i][j-1];
}else{
dp[i][j]=dp[i][j-1];
}
}
}
return dp[t.length()][s.length()];
}
}