Leetcode 115. 不同的子序列 详解 - Go语言中文社区

Leetcode 115. 不同的子序列 详解


115. 不同的子序列
给定一个字符串 S 和一个字符串 T,计算在 S 的子序列中 T 出现的个数。
一个字符串的一个子序列是指,通过删除一些(也可以不删除)字符且不干扰剩余字符相对位置所组成的新字符串。(例如,“ACE” 是 “ABCDE” 的一个子序列,而 “AEC” 不是)
示例 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
^^^
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/distinct-subsequences
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

挺难的一题。
刚拿到手,没头绪,仔细去想,先用递归吧。这种求方法数和最优解等等的要么用递归要么用dp。
修修改改的递归写法

class Solution {
    public int numDistinct(String s, String t) {
        int n = s.length();
        int m = t.length();
        return dfs(s, t, n - 1, m - 1);
    	}
    	public int dfs(String s, String t, int index1, int index2) {
    		if(index2 <= -1) return 1; //当t全部匹配完,可以算一种方法
    		if(index1 <= -1) return 0; //注意两个if的顺序正确
    		
    		if(s.charAt(index1) == t.charAt(index2)) {
    			return dfs(s, t, index1 - 1, index2 - 1) + dfs(s, t, index1 - 1, index2);
    		}
    		else return dfs(s, t, index1 - 1, index2);
    	}
    }

对是对了,就是超时
这个写法思路是啥呢,从最后开始匹配, index1和index2作为下标,如果对应的字符相等,我们可以继续往前匹配,也可以将s的下标前移一个,而index2不动,这是两种选择,而如果index2移到了0之前,那说明肯定有一种方法了,这个时候返回1,注意两个if的顺序,如果反一下就不对了。
但如果不等的话,那可以要将s的下标往前移去找和t里面相匹配的字符了。
只有一种选择。
这个写法我也琢磨了挺久的,还是菜啊。
然后意料之中的超时了,可以优化一下,存中间状态。

class Solution {
    public int numDistinct(String s, String t) {
        int n = s.length();
        int m = t.length();
        return dfs(s, t, n - 1, m - 1);
    }
    public int dfs(String s, String t, int index1, int index2) {
        if(index2 <= -1) return 1;
        if(index1 <= -1) return 0;
        int ans1 = dfs(s, t, index1 - 1, index2);
        if(s.charAt(index1) == t.charAt(index2)) {
            int ans2 = dfs(s, t, index1 - 1, index2 - 1);
            return ans1 + ans2;
        }
        else return ans1;
    }
}

结果很不给面子的两种都超时了,没办法那就用dp的方法吧…
在这里插入图片描述

有了递归的思路,写dp就要容易多了,改几行,初始化一下,其实dp就基本写好了。

class Solution {
    public int numDistinct(String s, String t) {
        int n = s.length();
        int m = t.length();
        if(m > n) return 0;
        int[][] dp = new int[m + 1][n + 1];
        for(int i = 0; i <= n; i ++) {
            dp[0][i] = 1;
        }
        for(int i = 1; i <= m; i ++) {
            for(int j = 1; j <= n; j ++) {
                if(t.charAt(i - 1) == s.charAt(j - 1)) {
                    dp[i][j] = dp[i][j - 1] + dp[i - 1][j - 1];
                }
                else dp[i][j] = dp[i][j - 1];
            }
        }
        return dp[m][n];
    }
}

除了边界情况有点坑…其他还好,效率一般般,50+,毕竟是二维的,也可以用dp[n][m]的形式来写…然后可以优化为一维数组,效率要提高不少。
这里我就不写了。
我觉得这道题还是挺难的。大家可以尝试先从递归写然后逐步优化。

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_43557402/article/details/91874163
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-02-25 02:26:03
  • 阅读 ( 1133 )
  • 分类:算法

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢