代码随想录算法训练营 动态规划part15

一、判断子序列

392. 判断子序列 - 力扣(LeetCode)

复制代码
class Solution {
    public boolean isSubsequence(String s, String t) {
        int n = s.length(), m = t.length();

        int[][] f = new int[m + 1][26];
        for (int i = 0; i < 26; i++) {
            f[m][i] = m;
        }

        for (int i = m - 1; i >= 0; i--) {
            for (int j = 0; j < 26; j++) {
                if (t.charAt(i) == j + 'a')
                    f[i][j] = i;
                else
                    f[i][j] = f[i + 1][j];
            }
        }
        int add = 0;
        for (int i = 0; i < n; i++) {
            if (f[add][s.charAt(i) - 'a'] == m) {
                return false;
            }
            add = f[add][s.charAt(i) - 'a'] + 1;
        }
        return true;
    }
}

二、不同的子序列

115. 不同的子序列 - 力扣(LeetCode)

定义 fij 为考虑 s 中 0,i 个字符,t 中 0,j 个字符的匹配个数。

那么显然对于某个 fij 而言,从「最后一步」的匹配进行分析,包含两类决策:

不让 si 参与匹配,也就是需要让 s 中 0,i−1个字符去匹配 t 中的 0,j 字符。此时匹配值为 fi−1j

让 si 参与匹配,这时候只需要让 s 中 0,i−1个字符去匹配 t 中的 0,j−1字符即可,同时满足 si=tj。此时匹配值为 fi−1j−1

最终 fijf就是两者之和。

复制代码
class Solution {
    public int numDistinct(String s, String t) {
        // 技巧:往原字符头部插入空格,这样得到 char 数组是从 1 开始
        // 同时由于往头部插入相同的(不存在的)字符,不会对结果造成影响,而且可以使得 f[i][0] = 1,可以将 1 这个结果滚动下去
        int n = s.length(), m = t.length();
        s = " " + s;
        t = " " + t;
        char[] cs = s.toCharArray(), ct = t.toCharArray();
        // f(i,j) 代表考虑「s 中的下标为 0~i 字符」和「t 中下标为 0~j 字符」是否匹配
        int[][] f = new int[n + 1][m + 1];
        // 原字符只有小写字符,当往两个字符插入空格之后,f[i][0] = 1 是一个显而易见的初始化条件
        for (int i = 0; i <= n; i++) f[i][0] = 1;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                // 包含两种决策:
                // 不使用 cs[i] 进行匹配,则有 f[i][j] = f[i - 1][j]
                f[i][j] = f[i - 1][j];
                // 使用 cs[i] 进行匹配,则要求 cs[i] == ct[j],然后有  f[i][j] += f[i - 1][j - 1]
                if (cs[i] == ct[j]) {
                    f[i][j] += f[i - 1][j - 1];
                } 
            }
        }
        return f[n][m];
    }
}
相关推荐
旖-旎4 小时前
《LeetCode 130 被围绕的区域 FloodFill DFS 解法》
c++·算法·深度优先·力扣·floodfill
林森lsjs4 小时前
斐波那契数列的 N 种解法:从递归到动态规划的优化之路【算法思考】
算法·动态规划
apcipot_rain5 小时前
计科八股20260616(1)——堆存中位数、链表判环、黑白测试、敏捷开发与瀑布模型、配置管理、持续集成、池化
数据结构·算法·软件工程
JAVA面经实录91712 小时前
Java 数据结构与算法 (终极完整学习文档)
java·数据结构·算法
开源Z13 小时前
LeetCode 42 · 接雨水:从暴力到双指针的三步优化
算法·leetcode
旖-旎13 小时前
《LeetCode 695 岛屿的最大面积 FloodFill DFS 解法》
c++·算法·力扣·深度优先遍历·floodfill
syagain_zsx14 小时前
STL 之 vector 讲练结合
c++·算法
MartinYeung515 小时前
[论文学习]DP2Unlearning:高效且具保证的大型语言模型遗忘框架(基于差分隐私的 LLM Unlearning 方法)
学习·算法·语言模型
Tian_Hang16 小时前
C++原型模式(Protype)
开发语言·c++·算法