IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> LeetCode·392.判断子序列·动态规划 -> 正文阅读

[数据结构与算法]LeetCode·392.判断子序列·动态规划

链接:https://leetcode.cn/problems/is-subsequence/solution/-by-xun-ge-v-c0pu/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。?

题目

?

示例

?

思路

方法一

  • 确定dp数组(dp table)以及下标的含义

dp[i][j] 表示以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,相同子序列的长度为dp[i][j]。

注意这里是判断s是否为t的子序列。即t的长度是大于等于s的。

  • 确定递推公式

在确定递推公式的时候,首先要考虑如下两种操作,整理如下:

  • if (s[i - 1] == t[j - 1])
    • t中找到了一个字符在s中也出现了
  • if (s[i - 1] != t[j - 1])
    • 相当于t要删除元素,继续匹配

if (s[i - 1] == t[j - 1]),那么dp[i][j] = dp[i - 1][j - 1] + 1;,因为找到了一个相同的字符,相同子序列长度自然要在dp[i-1][j-1]的基础上加1(如果不理解,在回看一下dp[i][j]的定义)

if (s[i - 1] != t[j - 1]),此时相当于t要删除元素,t如果把当前元素t[j - 1]删除,那么dp[i][j] 的数值就是 看s[i - 1]与 t[j - 2]的比较结果了,即:dp[i][j] = dp[i][j - 1];

  • dp数组如何初始化

从递推公式可以看出dp[i][j]都是依赖于dp[i - 1][j - 1] 和 dp[i][j - 1],所以dp[0][0]和dp[i][0]是一定要初始化的。

这里大家已经可以发现,在定义dp[i][j]含义的时候为什么要表示以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,相同子序列的长度为dp[i][j]。

方法二
对于思考题的思路
这种类似对同一个长字符串做很多次匹配的 ,可以像 KMP 算法一样,先用一些时间将长字符串中的数据 提取出来,磨刀不误砍柴功。有了提取好的数据,就可以快速的进行匹配。

  • 1.我们需要提取什么样的数据

这道题其实是贪心算法,上面的整个算法很简单,容易理解(是因为人都是贪心的吗 233)。 这里需要的数据就是匹配到某一点时 待匹配的字符在长字符串中 下一次 出现的位置。

所以我们前期多做一点工作,将长字符串研究透彻,假如长字符串的长度为 nn,建立一个 n * 26 大小的矩阵,表示每个位置上26个字符下一次出现的位置。实现如下:

? ? int dp[n][26];
? ? memset(dp, 0, sizeof(dp));
? ? for (char c = 'a'; c <= 'z'; c++) {
? ? int nextPos = -1; //表示接下来再不会出现该字符

? ? for (int i = len2 - 1; i>= 0; i--) { ?//为了获得下一个字符的位置,要从后往前
? ? ? ? dp[i][c - 'a'] = nextPos;
? ? ? ? if (t[i] == c)
? ? ? ? ? ? nextPos = i;
? ? }

  • 2.数据的利用

对于要匹配的短字符串,遍历每一个字符,不断地寻找该字符在长字符串中的位置,然后将位置更新,寻找下一个字符,相当于在长字符串上“跳跃”。

如果下一个位置为 -1,表示长字符串再没有该字符了,返回 false 即可。

如果能正常遍历完毕,则表示可行,返回 true

? ? int index = 0;
? ? for (int i = 0; i < lens; i++) {
? ? ? ? index = dp[index][s[i] - 'a'];
? ? ? ? if (index == -1)
? ? ? ? ? ? return false;
? ? }
? ? return true;

  • 3.需要注意的一点

对于 "abc" 在 "ahbgdc" 上匹配的时候,由于长字符串第一个 a 的下一个出现 a 的位置为 -1(不出现),会导致一个 bug。

所以在生成数组时在长字符串前插入一个空字符(相当于哨兵)即可。

代码

#define MAX(a, b) ((a) > (b) ? (a) : (b))

bool isSubsequence(char * s, char * t){
    int lens = strlen(s);
    int lent = strlen(t);
    int dp[lens+1][lent+1];
    memset(dp, 0, sizeof(dp));//初始化
    int max = 0;
    for(int i = 1; i <= lens; i++)
    {
        for(int j = 1; j <= lent; j++)//枚举数组元素
        {
            if(s[i-1] == t[j-1])//相同元素 + 1 
            {
                dp[i][j] = dp[i-1][j-1] + 1;
            }
            else//不需要,保存最大上一个相同值
            {
                dp[i][j] = dp[i][j-1];
            }
            max = MAX(max, dp[i][j]);
        }
    }
    return max == lens ? 1 : 0;
}

作者:xun-ge-v
链接:https://leetcode.cn/problems/is-subsequence/solution/-by-xun-ge-v-c0pu/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-09-30 01:12:58  更:2022-09-30 01:13:05 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 19:21:04-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码