判断子序列:
编辑距离入门问题
数组定义: 表示以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,相同子序列的长度为dp[i][j]
递推公式:
if (s[i - 1] == t[j - 1]), 说明t中找到了一个字符在s中也出现了, 那么dp[i-1][j-1] + 1
if (s[i - 1] != t[j - 1]), 相当于t要删除元素,继续匹配, 删除元素就是dp[i][j-1]
初始化: 根据递推公式可以发现dp[0][0]和dp[i][0]是必须初始化的, 是为0的,可以省略
最后判断长度是否相等
细节统一:
- class Solution {
- public boolean isSubsequence(String s, String t) {
- int len1 = s.length();
- int len2 = t.length();
- int[][] dp = new int[len1 + 1][len2 + 1];
- //直接开始遍历, 注意两个初始化定义是i-1;j-1, 所以<=
- for(int i = 1; i <= len1; i++){
- for(int j = 1; j <= len2; j++){
- //这里有两种情况
- //如果相等就+1
- if(s.charAt(i - 1) == t.charAt(j - 1)){
- dp[i][j] = dp[i - 1][j - 1] + 1;
- } else {
- //否则就得把t数组减一个
- dp[i][j] = dp[i][j - 1];
- }
- }
- }
- //最后判断一下数组长度是不是一模一样
- //由于定义, 这里不是len1-1
- if(dp[len1][len2] == len1){
- return true;
- } else {
- return false;
- }
- }
- }
双指针解法:
- class Solution {
- public boolean isSubsequence(String s, String t) {
- int len1 = s.length();
- int len2 = t.length();
- int i = 0, j = 0;
- while(i < len1 && j < len2){
- if(s.charAt(i) == t.charAt(j)){
- //i最后用来判断是否成功移动到s的末尾了
- i++;
- }
- //j一直向前移动
- j++;
- }
- return i == len1;
- }
- }
不同的子序列
(这一题和上一题s和t反过来了, 现在t是子序列)
给两个字符串, 计算s的子序列中t出现的个数(有多少种方式可以获得子序列)
- class Solution {
- public int numDistinct(String s, String t) {
- int len1 = s.length();
- int len2 = t.length();
- int[][] dp = new int[len1 + 1][len2 + 1];
- //初始化先, 这里是初始化[i][0]; 下面初始化[0][j]可以忽略
- for(int i = 0; i <= len1; i++){
- dp[i][0] = 1;
- }
- //开始遍历
- for(int i = 1; i <= len1; i++){
- for(int j = 1; j <= len2; j++){
- //如果相等, 那么加上两种情况的组合个数
- if(s.charAt(i - 1) == t.charAt(j - 1)){
- dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
- } else {
- //不相等, 那么s-1继续找
- dp[i][j] = dp[i - 1][j];
- }
- }
- }
- return dp[len1][len2];
- }
- }