DAY 58 动态规划

动态规划

● 392.判断子序列
● 115.不同的子序列

编辑距离

对于s和t,用dp[i][j]表示s中前i个元素和t中前j个元素的所求关系。
判断s[i - 1]和t[j - 1]:均认为是第一次比较该元素,因为比较完成后该值会存储,故若两者相等,则dp[i][j]= f(dp[i - 1][j - 1])
若两者不相等,对s或t执行操作,以编辑距离为例,s或t均可执行增删替换三种操作,可分为s添加元素(相当于t删除元素)、s删除元素、s替换(s和t均删除元素)三种情况。以第一种s添加元素为例,添加元素,则s中前i个元素与t中前j-1个元素已匹配,添加元素操作代码中体现为+1;第二种s删除元素,是为了和t的第j个(下标j-1)元素匹配,则删除后,s中前i-1个元素与t中前j个元素已匹配,删除元素操作代码中体现为+1;第三种,两者均删除元素,相当于s中前i-1个元素和t中前j-1 个元素已匹配,两者的删除认为占操作数1。

重要:

子序列问题,子序列是不改变的,回退操作在长序列中发生,递推公式相应下标来自长序列
而此处的回退可理解为长序列的删除操作,推到编辑距离,区别在于,编辑距离的:1.两个序列都可以操作;2.删除、替换(两个序列均删除)、添加(另一个序列的删除),多种操作,均可转换为某一序列的删除,问题简化完成

392.判断子序列

392.判断子序列

题目描述

给定字符串 s 和 t ,判断 s 是否为 t 的子序列。

字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。

进阶:

如果有大量输入的 S,称作 S1, S2, … , Sk 其中 k >= 10亿,你需要依次检查它们是否为 T 的子序列。在这种情况下,你会怎样改变代码?

示例:
输入:s = “abc”, t = “ahbgdc”
输出:true

思路

1.dp数组含义

dp[i][j]指s中前i个字符和t中前j个字符的最大重复字符个数
目标:dp[s.size()][t.size()] == s.size()

2.dp递推公式
  1. s[i - 1] == t[j - 1]时:dp[i][j] = dp[i -1][j -1] + 1
  2. s[i - 1] != t[j - 1]时:dp[i][j] = max (dp[i -1][j], dp[i][j - 1]) = dp[i][j - 1]
    由于想判断s是t的子串,此处相当于t要删除t[j - 1]元素继续匹配,则最大匹配长度从dp[i][j-1]得到
    t是可操作的,对应代码是 j
3.dp初始化

dp[0][j]——s中前0个元素和t中任意长度的重复字符数均为0
dp[i][0]——t中前0个字符和s中任意长度的重复字符数均为0

代码

// dp[i][j]:s中前i个 和 t中前j个 重复字符的最大数目
// 1.s[i - 1] == t[j - 1]:dp[i][j] = dp[i - 1][j - 1] + 1;
// 2.s[i - 1] != t[j - 1]:dp[i][j] = dp[i][j - 1];//相当于删除t中t[j - 1],继续向后
// 初始化:s或t任前0个字符,与另一个串的匹配长度均为0
class Solution {
public:
    bool isSubsequence(string s, string t) {
        int m = s.size();
        int n = t.size();
        vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
        for (int i = 1; i <= m; i++)
        {
            for (int j = 1; j <= n; j++)
            {
                if (s[i - 1] == t[j - 1])
                {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                }
                else
                {
                    //dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
                    dp[i][j] = dp[i][j - 1];
                }
            }
        }
        if (dp[m][n] == s.size())
        {
            return true;
        }
        return false;
    }
};

115.不同的子序列

115.不同的子序列

题目描述

给你两个字符串 s 和 t ,统计并返回在 s 的 子序列 中 t 出现的个数。

题目数据保证答案符合 32 位带符号整数范围。

思路

1.dp含义

dp[i][j]表示s中前i个元素、t中前j个元素,此时在s的子序列中t出现的个数

2.递推公式

i , j 同时移动,s[i - 1] == t [j - 1]时,s 中 t 出现的次数取决于dp[i - 1][j - 1];考虑重复出现的字母,i 需要回退,累加之前的个数;
s[i - 1] != t [j - 1]时,s 中 i 移动,含义为 s 中前 i 个元素 出现 t 中前 j 个元素的个数等于 s 中前 i - 1个元素 出现 t 中前 j 个元素的个数【显然,因为这个元素不匹配,所以回退,回退操作发生在s中】
t是可操作的,对应代码是 j

3.dp初始化

相当于每个集合都有一个空集? s中出现 t 空(空集)的数目是1。

代码


// dp[i][j]:s的前i个字符 t中前j个字符 前者中后者出现的个数
class Solution {
public:
    int numDistinct(string s, string t) {
        int m = s.size();
        int n = t.size();
        vector<vector<int>> dp(m + 1,vector<int>(n + 1));
        for (int i = 0; i <= m; i++)
        {
            dp[i][0] = 1;
        }
        for (int i = 1; i <= m; i++)
        {
            for (int j = 1; j <= n; j++)
            {
                if (s[i - 1] == t[j - 1])
                {
                    dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1];
                }
                else
                {
                    dp[i][j] = dp[i - 1][j];
                }
            }
        }
        return dp[m][n];
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
项目:使用 JavaScript 编写的杀死幽灵游戏(附源代码) 杀死鬼魂游戏是使用 Vanilla JavaScript、CSS 和 HTML 画布开发的简单项目。这款游戏很有趣。玩家必须触摸/杀死游荡的鬼魂才能得分。您必须将鼠标悬停在鬼魂上 - 尽量得分。鬼魂在眨眼间不断从一个地方移动到另一个地方。您必须在 1 分钟内尽可能多地杀死鬼魂。 游戏制作 这个游戏项目只是用 HTML 画布、CSS 和 JavaScript 编写的。说到这个游戏的特点,用户必须触摸/杀死游荡的幽灵才能得分。游戏会根据你杀死的幽灵数量来记录你的总分。你必须将鼠标悬停在幽灵上——尽量得分。你必须在 1 分钟内尽可能多地杀死幽灵。游戏还会显示最高排名分数,如果你成功击败它,该分数会在游戏结束屏幕上更新。 该游戏包含大量的 javascript 以确保游戏正常运行。 如何运行该项目? 要运行此游戏,您不需要任何类型的本地服务器,但需要浏览器。我们建议您使用现代浏览器,如 Google Chrome 和 Mozilla Firefox。要玩游戏,首先,单击 index.html 文件在浏览器中打开游戏。 演示: 该项目为国外大神项目,可以作为毕业设计的项目,也可以作为大作业项目,不用担心代码重复,设计重复等,如果需要对项目进行修改,需要具备一定基础知识。 注意:如果装有360等杀毒软件,可能会出现误报的情况,源码本身并无病毒,使用源码时可以关闭360,或者添加信任。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值