代码随想录-Day51

news2024/9/21 4:22:05

115. 不同的子序列

给你两个字符串 s 和 t ,统计并返回在 s 的 子序列 中 t 出现的个数,结果需要对 109 + 7 取模。

示例 1:

输入:s = “rabbbit”, t = “rabbit”
输出:3
解释:
如下所示, 有 3 种可以从 s 中得到 “rabbit” 的方案。
rabbbit
rabbbit
rabbbit
示例 2:

输入:s = “babgbag”, t = “bag”
输出:5
解释:
如下所示, 有 5 种可以从 s 中得到 “bag” 的方案。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

这段代码是用于解决「不同子序列」问题的Java实现,实质上是计算字符串 t 在字符串 s 中的不同子序列出现的次数。给定两个字符串 st,目标是找出 ts 中有多少种不同的子序列出现方式。

代码解析

  1. 初始化动态规划数组:

    • 创建一个二维数组 dp,其大小为 (s.length() + 1) x (t.length() + 1)dp[i][j] 的值代表 s 的前 i 个字符和 t 的前 j 个字符组成的子序列的出现次数。额外的一列是为了方便边界条件的处理,其中 dp[i][0] 的值默认为1,因为任何字符串都是空字符串的子序列,且只有一种方式。
  2. 动态规划迭代:

    • 从1到 s.length() 遍历 s 的每个字符,从1到 t.length() 遍历 t 的每个字符。
    • 对于 s 的第 i 个字符和 t 的第 j 个字符:
      • 如果两个字符相等,那么 s 的前 i 个字符和 t 的前 j 个字符组成的子序列的出现次数等于 s 的前 i-1 个字符和 t 的前 j-1 个字符组成的子序列的出现次数加上 s 的前 i-1 个字符和 t 的前 j 个字符组成的子序列的出现次数,即 dp[i - 1][j - 1] + dp[i - 1][j]
      • 如果两个字符不相等,那么出现次数等于 s 的前 i-1 个字符和 t 的前 j 个字符组成的子序列的出现次数,即 dp[i - 1][j]
  3. 返回结果:

    • 最后返回 dp[s.length()][t.length()],即 ts 中的不同子序列出现的次数。

时间复杂度和空间复杂度

  • 时间复杂度: O(m * n),其中 m 和 n 分别是字符串 st 的长度。这是因为需要遍历两个字符串的所有可能的字符组合来计算子序列的出现次数。
  • 空间复杂度: O(m * n),需要一个大小为 (m + 1) x (n + 1) 的动态规划数组 dp 来存储中间结果。

总结

这段代码通过动态规划的方法,有效地解决了不同子序列计数问题。尽管时间复杂度和空间复杂度较高,但在许多实际应用场景中,这样的性能通常是可接受的,特别是当字符串长度适中时。如果需要进一步优化空间复杂度,可以考虑使用滚动数组技术,将空间复杂度降低到 O(min(m, n)),但这通常会增加代码的复杂度。在处理此类问题时,权衡时间和空间资源是一个常见的考量因素。

583. 两个字符串的删除操作

给定两个单词 word1 和 word2 ,返回使得 word1 和 word2 相同所需的最小步数。

每步 可以删除任意一个字符串中的一个字符。

示例 1:

输入: word1 = “sea”, word2 = “eat”
输出: 2
解释: 第一步将 “sea” 变为 “ea” ,第二步将 "eat "变为 “ea”
示例 2:

输入:word1 = “leetcode”, word2 = “etco”
输出:4
在这里插入图片描述

方法一:

// dp数组中存储word1和word2最长相同子序列的长度
class Solution {
    public int minDistance(String word1, String word2) {
        int len1 = word1.length();
        int len2 = word2.length();
        int[][] dp = new int[len1 + 1][len2 + 1];

        for (int i = 1; i <= len1; i++) {
            for (int j = 1; j <= len2; j++) {
                if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }

        return len1 + len2 - dp[len1][len2] * 2;
    }
}

这段代码是用于解决「编辑距离之最短编辑脚本」问题的Java实现,但其计算方法并不直接针对编辑距离,而是利用了最长公共子序列(LCS, Longest Common Subsequence)的概念。给定两个字符串 word1word2,目标是计算将 word1 转换为 word2 所需的最少编辑操作数,这里的编辑操作包括插入、删除和替换一个字符。

代码解析

  1. 初始化动态规划数组:

    • 创建一个二维数组 dp,其大小为 (len1 + 1) x (len2 + 1)dp[i][j] 的值代表 word1 的前 i 个字符和 word2 的前 j 个字符的最长公共子序列的长度。额外的一列和一行是为了方便边界条件的处理。
  2. 动态规划迭代:

    • 从1到 len1 遍历 word1 的每个字符,从1到 len2 遍历 word2 的每个字符。
    • 对于 word1 的第 i 个字符和 word2 的第 j 个字符:
      • 如果两个字符相等,那么 word1 的前 i 个字符和 word2 的前 j 个字符的最长公共子序列的长度等于 word1 的前 i-1 个字符和 word2 的前 j-1 个字符的最长公共子序列的长度加1,即 dp[i-1][j-1] + 1
      • 如果两个字符不相等,那么最长公共子序列的长度等于 word1 的前 i-1 个字符和 word2 的前 j 个字符的最长公共子序列的长度与 word1 的前 i 个字符和 word2 的前 j-1 个字符的最长公共子序列的长度中的较大值,即 Math.max(dp[i-1][j], dp[i][j-1])
  3. 计算编辑距离:

    • 最长公共子序列的长度可以被视为两个字符串共享的字符数量。为了将 word1 转换成 word2,我们需要删除 word1 中不在公共子序列中的字符,并在适当位置插入 word2 中不在公共子序列中的字符。因此,编辑距离等于 word1word2 的长度之和减去两倍的最长公共子序列的长度,即 len1 + len2 - dp[len1][len2] * 2

时间复杂度和空间复杂度

  • 时间复杂度: O(m * n),其中 m 和 n 分别是字符串 word1word2 的长度。这是因为需要遍历两个字符串的所有可能的字符组合来计算最长公共子序列的长度。
  • 空间复杂度: O(m * n),需要一个大小为 (m + 1) x (n + 1) 的动态规划数组 dp 来存储中间结果。

总结

这段代码通过计算最长公共子序列并利用其长度来间接计算编辑距离,提供了一种有效的解决方案。尽管它并没有直接使用编辑距离的动态规划公式,但通过巧妙地利用最长公共子序列的概念,仍然达到了计算编辑距离的目的。这种间接的方法有时在处理某些变体问题时会更加灵活和直观。如果需要进一步优化空间复杂度,可以考虑使用滚动数组技术,将空间复杂度降低到 O(min(m, n)),但这可能会使代码变得更复杂。

方法二:

// dp数组中存储需要删除的字符个数
class Solution {
    public int minDistance(String word1, String word2) {
        int[][] dp = new int[word1.length() + 1][word2.length() + 1];
        for (int i = 0; i < word1.length() + 1; i++) dp[i][0] = i;
        for (int j = 0; j < word2.length() + 1; j++) dp[0][j] = j;
        
        for (int i = 1; i < word1.length() + 1; i++) {
            for (int j = 1; j < word2.length() + 1; j++) {
                if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1];
                }else{
                    dp[i][j] = Math.min(dp[i - 1][j - 1] + 2,
                                        Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1));
                }
            }
        }
        
        return dp[word1.length()][word2.length()];
    }
}

这段代码是用于解决「编辑距离」问题的Java实现,该问题要求计算将字符串 word1 转换为字符串 word2 所需的最小编辑操作数。编辑操作包括插入、删除和替换一个字符。代码通过动态规划方法实现,直接计算最小编辑距离。

代码解析

  1. 初始化动态规划数组:

    • 创建一个二维数组 dp,其大小为 (word1.length() + 1) x (word2.length() + 1)dp[i][j] 的值代表将 word1 的前 i 个字符转换为 word2 的前 j 个字符所需的最小编辑操作数。额外的一列和一行是为了方便边界条件的处理,其中 dp[i][0] 的值初始化为 idp[0][j] 的值初始化为 j,因为将一个字符串转换为空字符串或从空字符串转换为一个字符串所需的操作数分别为字符串的长度。
  2. 动态规划迭代:

    • 从1到 word1.length() + 1 遍历 word1 的每个字符,从1到 word2.length() + 1 遍历 word2 的每个字符。
    • 对于 word1 的第 i 个字符和 word2 的第 j 个字符:
      • 如果两个字符相等,那么将 word1 的前 i 个字符转换为 word2 的前 j 个字符所需的最小编辑操作数等于将 word1 的前 i-1 个字符转换为 word2 的前 j-1 个字符所需的最小编辑操作数,即 dp[i - 1][j - 1]
      • 如果两个字符不相等,那么最小编辑操作数等于以下三种操作中的最小值:
        • word1 的第 i 个字符替换为 word2 的第 j 个字符,加上将 word1 的前 i-1 个字符转换为 word2 的前 j-1 个字符所需的最小编辑操作数加2(因为替换操作成本定义为2)。
        • 删除 word1 的第 i 个字符,加上将 word1 的前 i-1 个字符转换为 word2 的前 j 个字符所需的最小编辑操作数加1。
        • word1 的前 i 个字符后插入 word2 的第 j 个字符,加上将 word1 的前 i 个字符转换为 word2 的前 j-1 个字符所需的最小编辑操作数加1。
  3. 返回结果:

    • 最后返回 dp[word1.length()][word2.length()],即 word1 转换为 word2 所需的最小编辑操作数。

时间复杂度和空间复杂度

  • 时间复杂度: O(m * n),其中 m 和 n 分别是字符串 word1word2 的长度。这是因为需要遍历两个字符串的所有可能的字符组合来计算最小编辑操作数。
  • 空间复杂度: O(m * n),需要一个大小为 (m + 1) x (n + 1) 的动态规划数组 dp 来存储中间结果。

总结

这段代码通过动态规划方法,有效地解决了编辑距离问题,直接计算出将一个字符串转换为另一个字符串所需的最小编辑操作数。如果需要进一步优化空间复杂度,可以考虑使用滚动数组技术,将空间复杂度降低到 O(min(m, n)),但这可能会使代码变得更加复杂。在实际应用中,选择合适的优化策略取决于具体的需求和资源限制。

方法三:

//DP - longest common subsequence (用最長公共子序列反推)
class Solution {
    public int minDistance(String word1, String word2) {
        char[] char1 = word1.toCharArray();
        char[] char2 = word2.toCharArray();

        int len1 = char1.length;
        int len2 = char2.length;

        int dp[][] = new int [len1 + 1][len2 + 1];

        for(int i = 1; i <= len1; i++){
            for(int j = 1; j <= len2; j++){
                if(char1[i - 1] == char2[j - 1])
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                else
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
            }
        }

        return len1 + len2 - (2 * dp[len1][len2]);//和leetcode 1143只差在這一行。
    }
}

这段代码是用于解决「编辑距离」问题的Java实现,但它实际上是通过计算两个字符串 word1word2 的最长公共子序列(LCS, Longest Common Subsequence)的长度,然后基于这个信息来间接计算编辑距离。这种方法的思路是,编辑距离可以看作是两个字符串各自去除最长公共子序列部分后,剩下的字符数总和。

代码解析

  1. 初始化动态规划数组:

    • 创建一个二维数组 dp,其大小为 (len1 + 1) x (len2 + 1)dp[i][j] 的值代表 word1 的前 i 个字符和 word2 的前 j 个字符的最长公共子序列的长度。额外的一列和一行是为了方便边界条件的处理。
  2. 动态规划迭代:

    • 从1到 len1 遍历 word1 的每个字符,从1到 len2 遍历 word2 的每个字符。
    • 对于 word1 的第 i 个字符和 word2 的第 j 个字符:
      • 如果两个字符相等,那么 word1 的前 i 个字符和 word2 的前 j 个字符的最长公共子序列的长度等于 word1 的前 i-1 个字符和 word2 的前 j-1 个字符的最长公共子序列的长度加1,即 dp[i-1][j-1] + 1
      • 如果两个字符不相等,那么最长公共子序列的长度等于 word1 的前 i-1 个字符和 word2 的前 j 个字符的最长公共子序列的长度与 word1 的前 i 个字符和 word2 的前 j-1 个字符的最长公共子序列的长度中的较大值,即 Math.max(dp[i-1][j], dp[i][j-1])
  3. 计算编辑距离:

    • 最长公共子序列的长度可以被视为两个字符串共享的字符数量。为了将 word1 转换成 word2,我们需要删除 word1 中不在公共子序列中的字符,并在适当位置插入 word2 中不在公共子序列中的字符。因此,编辑距离等于 word1word2 的长度之和减去两倍的最长公共子序列的长度,即 len1 + len2 - (2 * dp[len1][len2])

时间复杂度和空间复杂度

  • 时间复杂度: O(m * n),其中 m 和 n 分别是字符串 word1word2 的长度。这是因为需要遍历两个字符串的所有可能的字符组合来计算最长公共子序列的长度。
  • 空间复杂度: O(m * n),需要一个大小为 (m + 1) x (n + 1) 的动态规划数组 dp 来存储中间结果。

总结

这段代码通过计算最长公共子序列并利用其长度来间接计算编辑距离,提供了一种有效的解决方案。尽管这种方法并不是直接计算编辑距离的标准动态规划公式,但通过计算最长公共子序列的长度,然后根据这个信息推导出编辑距离,同样能高效地解决问题。这种方法在某些情况下可能更为直观,尤其是在理解最长公共子序列概念的基础上。如果需要进一步优化空间复杂度,可以考虑使用滚动数组技术,将空间复杂度降低到 O(min(m, n)),但这可能会使代码变得更复杂。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1907369.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【SMPL简介】SMPL: A Skinned Multi-Person Linear Model【源码复现】

【SMPL简介】SMPL: A Skinned Multi-Person Linear Model【源码复现】 一、前言环境搭建运行demo.py 参考链接 一、前言 SMPL是一种3D人体建模方法.在数字人或者人物角色三维重建领域有着广泛应用 支持人体的各种形状及动作 可以简单理解为通过训练获取的人物模型 常用的模型有…

信息技术课堂纪律管理:从混乱到秩序的智慧转型

引言&#xff1a; 在信息爆炸的时代&#xff0c;信息技术课程如同一把开启未来世界大门的钥匙&#xff0c;为学生们搭建起探索科技奥秘的桥梁。然而&#xff0c;面对着屏幕背后的无限诱惑&#xff0c;维持课堂纪律&#xff0c;确保学生们专注于学习&#xff0c;成为了每位信息…

Flask项目搭建及部署 —— Python

flask搭建及部署 pip 19.2.3 python 3.7.5 Flask 1.1.1 Flask-SQLAlchemy 2.4.1 Pika 1.1.0 Redis 3.3.11 flask-wtf 0.14.2 1、创建flask项目&#xff1a; 创建完成后整个项目结构树&#xff1a; app.py: 项⽬管理⽂件&#xff0c;通过它管理项⽬。 static: 存放静态…

使用tcpdump抓取本本机的所有icmp包

1、抓取本机所有icmp包 tcpdump -i any icmp -vv 图中上半部分&#xff0c;是源主机tmp179无法ping通目标主机192.168.10.79&#xff08;因为把该主机关机了&#xff09;的状态&#xff0c;注意看&#xff0c;其中有unreachable 图中下半部分&#xff0c;是源主机tmp179可以p…

张量分解(2)——张量运算(内积、外积、直积、范数)

&#x1f345; 写在前面 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;这里是hyk写算法了吗&#xff0c;一枚致力于学习算法和人工智能领域的小菜鸟。 &#x1f50e;个人主页&#xff1a;主页链接&#xff08;欢迎各位大佬光临指导&#xff09; ⭐️近…

国内仅存的3个完美替代Google安卓商店的APP与网站

Google安卓商店在国内访问限制&#xff0c;部分谷歌商店镜像站点也相继受限&#xff0c;现分享目前仍可在国内顺畅使用的应用程序商店与网站资源&#xff0c;请大家且用且珍惜。 2024年7月8日国内验证有效的资源 F-Droid 简介&#xff1a;F-Droid&#xff0c;专注于开源软件的…

独立站爆款产品的选品思路及底层逻辑拆解

在这个竞争激烈的跨境电商市场&#xff0c;有一件事情比网站设计、营销策略、物流服务都更重要。那就是选品。跨境独立站选品是独立站成功的第一步&#xff0c;如果选错了产品&#xff0c;那么所有努力都可能白费。可能会面临库存积压、利润低迷、客户流失等问题。但是如果选对…

从数据到洞察:DataOps加速AI模型开发的秘密实践大公开!

作者 | 代立冬&#xff0c;白鲸开源科技联合创始人&CTO 引言 在AI驱动的商业世界中&#xff0c;DataOps作为连接数据与洞察的桥梁&#xff0c;正迅速成为企业数据战略的核心。 在WOT全球技术创新大会2024北京站&#xff0c;白鲸开源联合创始人&CTO 代立冬 在「大数据…

NFT 技术在艺术领域的应用

NFT (Non-Fungible Token) 技术在艺术领域有着广泛的应用&#xff0c;为艺术家和艺术品收藏家带来了新的机遇和挑战。以下是 NFT 技术在艺术领域的一些主要应用。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 1. 数字艺术品确权和交…

【Spring Boot】Spring AOP动态代理,以及静态代理

目录 Spring AOP代理一. 代理的概念二. 静态代理三. JDK代理3.1 重写 invoke 方法进⾏功能增强3.2 通过Proxy类随机生成代理对象 四. CGLIB代理4.1 自定义类来重写intercept方法4.2 通过Enhancer类的create方法来创建代理类 五. AOP源码剖析 总结(重中之重&#xff0c;精华) Sp…

【人工智能】—基于成都市各区(市)县租房价格预测建模研究

引言 随着城市化进程的加速&#xff0c;人口流动日益频繁&#xff0c;租房市场作为城市生活的重要组成部分&#xff0c;其价格波动对居民生活质量和城市经济发展具有显著影响。成都市&#xff0c;作为中国西部地区的经济、文化、交通和科技中心&#xff0c;近年来吸引了大量人…

昇思25天学习打卡营第17天|linchenfengxue

RNN实现情感分类 概述 情感分类是自然语言处理中的经典任务&#xff0c;是典型的分类问题。本节使用MindSpore实现一个基于RNN网络的情感分类模型&#xff0c;实现如下的效果&#xff1a; 输入: This film is terrible 正确标签: Negative 预测标签: Negative输入: This fil…

1.8.0-矩阵乘法的反向传播-简单推导

1相关资料 之前分享过一个博客里面写的&#xff0c;我们大致了解并记住结论的博客&#xff1a;【深度学习】7-矩阵乘法运算的反向传播求梯度_矩阵梯度公式-CSDN博客&#xff1b;这里再分享一下自然语言处理书上关于这部分的推导过程&#xff1a;3-矩阵相乘-梯度反向传播的计算…

开源模型应用落地-FastAPI-助力模型交互-进阶篇(一)

一、前言 FastAPI 的高级用法可以为开发人员带来许多好处。它能帮助实现更复杂的路由逻辑和参数处理&#xff0c;使应用程序能够处理各种不同的请求场景&#xff0c;提高应用程序的灵活性和可扩展性。 在数据验证和转换方面&#xff0c;高级用法提供了更精细和准确的控制&#…

上海慕尼黑电子展开展,启明智显携物联网前沿方案亮相

随着科技创新的浪潮不断涌来&#xff0c;上海慕尼黑电子展在万众瞩目中盛大开幕。本次展会汇聚了全球顶尖的电子产品与技术解决方案&#xff0c;成为业界瞩目的焦点。启明智显作为物联网彩屏显示领域的佼佼者携产品亮相展会&#xff0c;为参展者带来了RTOS、LINUX全系列方案及A…

【见刊通知】MVIPIT 2023机器视觉、图像处理与影像技术国际会议

MVIPIT 2023&#xff1a;https://ieeexplore.ieee.org/xpl/conhome/10578343/proceeding 入库Ei数据库需等20-50天左右 第二届会议征稿启动&#xff08;MVIPIT 2024&#xff09; The 2nd International Conference on Machine Vision, Image Processing & Imaging Techn…

java —— tomcat 部署项目

一、通过 war 包部署 1、将项目导出为 war 包&#xff1b; 2、将 war 包放置在 tomcat 目录下的 webapps 文件夹下&#xff0c;该 war 包稍时便自动解析为项目文件夹&#xff1b; 3、启动 tomcat 的 /bin 目录下的 startup.bat 文件&#xff0c;此时即可从浏览器访问项目首页…

3.Python学习:模块\包\yaml

1.模块与包–互相引用 &#xff08;1&#xff09;一个模块就是一个.py文件 &#xff08;2&#xff09;有模块的目录–文件夹 &#xff08;3&#xff09;包&#xff1a;文件夹包含__init__.py文件 &#xff08;4&#xff09;导入包时&#xff0c;init.py文件里的内容会执行一次 …

聚鼎装饰画:装饰画喊个与现在是什么情况

回眸历史长河&#xff0c;装饰画以其独特的魅力一直为人类生活环境添彩增趣。从古埃及的壁画到文艺复兴时期的油画&#xff0c;再到现代简约的线条画&#xff0c;装饰画如同时代的缩影&#xff0c;映射出不同历史阶段的文化特征与审美趣味。 在现代社会&#xff0c;装饰画的现状…

C语言学习笔记[21]:分支语句if...else

C语言是结构化的程序设计语言 顺序结构选择结构循环结构 分支语句对应的就是选择结构&#xff0c;循环语句对应的就是循环结构 分支语句 if...elseswitch 循环语句 whilefordo...while goto语句 语句 C语言中由分号隔开的就是一条语句&#xff0c;比如&#xff1a; #…