【面试算法——动态规划 21】不同的子序列(hard) 通配符匹配(hard)

news2024/9/23 9:20:51

115. 不同的子序列

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

链接::https://leetcode.cn/problems/distinct-subsequences/

示例 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

1.状态表示*

dp[i][j] 表⽰:在字符串 s 的 [0, j] 区间内的所有⼦序列中,有多少个 t 字符串 [0,i] 区间内的⼦串.

2.状态转移方程
分析状态转移⽅程的经验就是根据「最后⼀个位置」的状况,分情况讨论。
对于 dp[i][j] ,我们可以根据 s1[i] 与 s2[j] 的字符分情况讨论:

  1. . 两个字符相同, s1[i] = s2[j] :那么最⻓公共⼦序列就在 s1 的 [0, i - 1] 以 及 s2 的 [0, j - 1] 区间上找到⼀个最⻓的,然后再加上 s1[i] 即可。因此 dp[i][j] = dp[i - 1][j - 1] + 1 ;
  2. ii. 两个字符不相同, s1[i] != s2[j] :那么最⻓公共⼦序列⼀定不会同时以 s1[i] 和 s2[j] 结尾。那么我们找最⻓公共⼦序列时,有下⾯三种策略:
    去 s1 的 [0, i - 1] 以及 s2 的 [0, j] 区间内找:此时最⼤⻓度为 dp[i - 1][j] ;
    去 s1 的 [0, i] 以及 s2 的 [0, j - 1] 区间内找:此时最⼤⻓度为 dp[i ] [j - 1] ;
    去s1 的 [0, i - 1] 以及 s2 的 [0, j - 1] 区间内找:此时最⼤⻓度为 dp[i - 1][j - 1]

我们要三者的最⼤值即可。但是我们细细观察会发现,第三种包含在第⼀种和第⼆种情况⾥⾯,但是我们求的是最⼤值,并不影响最终结果。因此只需求前两种情况下的最⼤值即可。
综上,状态转移⽅程为:

if(s1[i] == s2[j]) dp[i][j] = dp[i - 1][j - 1] + 1 ;
if(s1[i] != s2[j]) dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])

3. 初始化
a. 「空串」是有研究意义的,因此我们将原始 dp 表的规模多加上⼀⾏和⼀列,表⽰空串。
b. 引⼊空串后,⼤⼤的⽅便我们的初始化。
c. 但也要注意「下标的映射关系」,以及⾥⾯的值要「保证后续填表是正确的」。
当 s1 为空时,没有⻓度,同理 s2 也是。因此第⼀⾏和第⼀列⾥⾯的值初始化为 0 即可保证后续填表是正确的.

4. 填表顺序
根据「状态转移⽅程」得:从上往下填写每⼀⾏,每⼀⾏从左往右

5. 返回值
返回 dp[m][n]

代码:

  int numDistinct(string s, string t) {
       int m=t.size();
      int n=s.size();

      //dp[i][j]表示的是 以0~j范围内的所有s子序列中,有多少0~i的t字串
      vector<vector<double>> dp(m+1,vector<double>(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++)
          {
              dp[i][j]+=dp[i][j-1];
              if(t[i-1]==s[j-1])
              {
                  dp[i][j]+=dp[i-1][j-1];
              }
          }
      }
      return dp[m][n];
    }

在这里插入图片描述

44. 通配符匹配

链接:https://leetcode.cn/problems/wildcard-matching/description/

给你一个输入字符串 (s) 和一个字符模式 § ,请你实现一个支持 ‘?’ 和 ‘’ 匹配规则的通配符匹配:
‘?’ 可以匹配任何单个字符。
'
’ 可以匹配任意字符序列(包括空字符序列)。
判定匹配成功的充要条件是:字符模式必须能够 完全匹配 输入字符串(而不是部分匹配)。

示例 1:

输入:s = “aa”, p = “a”
输出:false
解释:“a” 无法匹配 “aa” 整个字符串。
示例 2:

输入:s = “aa”, p = ""
输出:true
解释:'
’ 可以匹配任意字符串。
示例 3:

输入:s = “cb”, p = “?a”
输出:false
解释:‘?’ 可以匹配 ‘c’, 但第二个 ‘a’ 无法匹配 ‘b’。

1.状态表示*

dp[i][j] 表⽰: p 字符串 [0, j] 区间内的⼦串能否匹配字符串 s 的 [0, i] 区间内的⼦串

2.状态转移方程
⽼规矩,根据最后⼀个位置的元素,结合题⽬要求,分情况讨论:

  1. i. 当 s[i] == p[j] 或 p[j] == ‘?’ 的时候,此时两个字符串匹配上了当前的⼀个字符,只能从 dp[i -
    1][j - 1] 中看当前字符前⾯的两个⼦串是否匹配。只能继承上个状态中的匹配结果, dp[i][j] = dp[i][j - 1] ;
  2. ii. 当 p[j] == ‘*’ 的时候,此时匹配策略有两种选择:
    • ⼀种选择是: * 匹配空字符串,此时相当于它匹配了⼀个寂寞,直接继承状态 dp[i] [j - 1] ,此时 dp[i][j] = dp[i][j -1] ;
    • 另⼀种选择是: * 向前匹配 1 ~ n 个字符,直⾄匹配上整个 s1 串。此时相当于从 dp[k][j - 1] (0 <= k <= i) 中所有匹配情况中,选择性继承可以成功的情况。此时 dp[i][j] = dp[k][j - 1] (0 <= k <= i) ;
  3. iii. 当 p[j] 不是特殊字符,且不与 s[i] 相等时,⽆法匹配。 三种情况加起来,就是所有可能的匹配结果。

综上所述,状态转移⽅程为:

▪ 当 s[i] == p[j] 或 p[j] == ‘?’ 时: dp[i][j] = dp[i][j - 1]
▪ 当 p[j] == ‘*’ 时,有多种情况需要讨论: dp[i][j] = dp[k][j - 1] (0 <=k <= i)

重难点
优化:当我们发现,计算⼀个状态的时候,需要⼀个循环才能搞定的时候,我们要想到去优化。优
化的⽅向就是⽤⼀个或者两个状态来表⽰这⼀堆的状态。通常就是把它写下来,然后⽤数学的⽅式
做⼀下等价替换:

当 p[j] == ‘*’ 时,状态转移⽅程为: dp[i][j] = dp[i][j - 1] || dp[i - 1][j - 1] || dp[i - 2][j - 1] …

我们发现 i 是有规律的减⼩的,因此我们去看看 dp[i - 1][j] :
dp[i - 1][j] = dp[i - 1][j - 1] || dp[i - 2][j - 1] || dp[i - 3][j - 1] …
我们惊奇的发现, dp[i][j] 的状态转移⽅程⾥⾯除了第⼀项以外,其余的都可以⽤ dp[i -
1][j] 替代。因此,我们优化我们的状态转移⽅程为: dp[i][j] = dp[i - 1][j] ||dp[i][j - 1]

3. 初始化
由于 dp 数组的值设置为是否匹配,为了不与答案值混淆,我们需要将整个数组初始化为false 。
由于需要⽤到前⼀⾏和前⼀列的状态,我们初始化第⼀⾏、第⼀列即可。

◦ dp[0][0] 表⽰两个空串能否匹配,答案是显然的,初始化为 true 。

  • ◦ 第⼀⾏表⽰ s 是⼀个空串, p 串和空串只有⼀种匹配可能,即 p 串表⽰为 “**" ,此时
    也相当于空串匹配上空串。所以,我们可以遍历 p 串,把所有前导为 "
    ” 的 p ⼦串和空串 的 dp 值设为 true 。
  • ◦ 第⼀列表⽰ p 是⼀个空串,不可能匹配上 s 串,跟随数组初始化即可。

4. 填表顺序
根据「状态转移⽅程」得:从上往下填写每⼀⾏,每⼀⾏从左往右

5. 返回值
返回 dp[m][n]

代码:

 bool isMatch(string s, string p) {
  int n=s.size();
        int m=p.size();

        vector<vector<bool>> dp(n+1,vector<bool>(m+1));
        //初始化
        dp[0][0]=1;
        for(int i=1;i<=m;i++)
        {
            if(p[i-1]=='*') dp[0][i]=1;
            else break;
        }
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                if(p[j-1]=='?'||s[i-1]==p[j-1])
                {
                    dp[i][j]=dp[i-1][j-1];
                }
                if(p[j-1]=='*')
                {
                    // for(int z=0;z<=i;z++)
                    // {
                    //     if(dp[z][j-1])
                    //     {
                    //         dp[i][j]=dp[z][j-1];
                    //         break;
                    //     }
                    // }
                    
                    //优化
                    dp[i][j] = dp[i - 1][j] || dp[i][j - 1];
                }
                
            }
        }
        return dp[n][m];
    

    }

在这里插入图片描述

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

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

相关文章

FreeRTOS自我救赎1之基本知识

每次写博客都是先用完了知识再写&#xff0c;也是很无奈&#xff0c;因为面试的时候我只会操作但我不会说&#xff0c;多写博客才能会“吹”。 1.目录结构 不好评价&#xff0c;我的目录结构是cubemx生成的&#xff0c;其中BSP_Device存储了一些模块化后的中间层代码 1.1核心…

【Java 进阶篇】使用Druid数据库连接池工具类进行测试

在前面的博客中&#xff0c;我们已经介绍了如何配置和使用Druid数据库连接池。现在&#xff0c;让我们来学习如何编写测试代码&#xff0c;以确保Druid连接池的正常运行。 步骤1&#xff1a;创建测试表 首先&#xff0c;我们需要创建一个测试用的数据库表&#xff0c;以便在示…

MongoDB——centOS7安装mongodb5.0.21版本服务端(图解版)

目录 一、mongodb官网下载地址二、安装步骤2.1、上传安装包并解压2.2、配置环境变量2.3、创建目录并授权2.4、创建配置文件2.5、启动MongoDB 三、开放端口四、客户端连接 一、mongodb官网下载地址 mongodb官网下载地址&#xff1a;https://www.mongodb.com/try/download/commu…

Android启动式服务

Github: https://github.com/MADMAX110/Joke 服务是与活动类似的应用组件&#xff0c;只不过服务没有用户界面。 使用服务可以一直在后台做某些事情&#xff0c;比如下载一个大文件&#xff0c;播放一段音乐或者监听来自服务器的一个消息。 有三种类型的服务&#xff1a; 1、启…

【UiPath】解决办法:There are no Unattended runtimes configured on this machine.

本文收录于【#摸鱼玩 UiPath】专栏中&#xff0c;记录在 RPA&#xff08;UiPath&#xff09;使用过程中&#xff0c;遇到的问题以及解决办法。 更多关于 RPA 技术内容敬请关注&#xff1a;【#摸鱼玩 UiPath】专栏。 文章目录 问题描述分析原因解决办法文末参考RPA 技术 UiPath…

【自动控制原理】Simulink搭建仿真模型(信号发生器、比较点、传递函数、示波器)

目录 一、前言 二、Simulink~自动控制原理 1、Simulink官方教程 2、开环系统、闭环系统 a. 开环系统 加干扰 b. 闭环系统 三、Simulink模型仿真 1、信号发生器 a. 阶跃信号发生器 b. 脉冲信号发生器 2、比较点 3、传递函数 a. 比例环节&#xff08;Proportional …

Xilisoft Video Converter Ultimate for Mac:让音视频转换变得更简单

无论是在工作还是娱乐中&#xff0c;我们都会遇到音视频格式不兼容的问题。这时候&#xff0c;一个好用的音视频格式转换工具就显得尤为重要。Xilisoft Video Converter Ultimate for Mac&#xff08;曦力音视频转换&#xff09;就是这样一款让您的音视频转换变得更简单的工具。…

嵌入式养成计划-37----C++内存动态分配与回收--C++类中特殊的成员函数

八十五、 C内存动态分配与回收 C语言中的动态内存分配和回收是用malloc、free来完成的C中也可以用上述两个函数来完成。C中也为用户提供了两个关键字来进行动态内存分配和回收 new 、delete 85.1 分配 单个内存分配 格式&#xff1a; 数据类型 *指针名 new 数据类型 例如&a…

uml图是什么?uml图中的各类箭头代表的是什么含义

一 UML图是什么&#xff1f; UML&#xff08;Unified Modeling Language&#xff09;是一种标准化的图形化建模语言&#xff0c;用于描述、分析、设计和表示软件系统的结构、行为、关系和交互。它提供了一组符号和规则&#xff0c;可以用于创建各种类型的图表&#xff0c;从…

大模型推理框架概述

从 ChatGPT 面世以来&#xff0c;引领了大模型时代的变革&#xff0c;除了大模型遍地开花以外&#xff0c;承载大模型进行推理的框架也是层出不穷&#xff0c;大有百家争鸣的态势。本文主要针对业界知名度较高的一些大模型推理框架进行相应的概述。 简介 vLLM是一个开源的大模…

序列化反射filter添加Neo-reGeorg内网代理

前言&#xff1a; 当被攻击服务器网络比较苛刻&#xff0c;可以选择通过filter添加Neo-reGeorg进行内网代理&#xff0c;这样做的好处首先通过反序列化漏洞&#xff0c;添加的filter在内存中&#xff0c;无文件落地可以防止杀软查杀。 基础&#xff1a; 首先我们先要了解如何…

Android 属性动画ValueAnimator整理

Android 属性动画有 ObjectAnimator 、AnimatorSet 、ValueAnimator 等。 ObjectAnimator 、AnimatorSet 参考前篇 Andorid 属性动画ObjectAnimation整理_南国樗里疾的博客-CSDN博客 本篇介绍 ValueAnimator &#xff0c;它本身不作用于任何对象&#xff0c;它是对值进行动画…

如何在小程序中设置导航栏文字颜色和背景颜色

不同商家有不同的颜色风格&#xff0c;例如有些做设计的公司&#xff0c;主要是黑色风格&#xff1b;有些卖珠宝的商家&#xff0c;主要是金色风格&#xff1b;他们的小程序&#xff0c;也需要进行同样的风格设定。下面具体介绍怎么在小程序中进行整个风格设定。 1. 在小程序管…

C# .net创建一个MVC框架工程

二、C# .net创建一个MVC框架工程 1.步骤 首先打开VS &#xff0c;然后点击创建新项目 在三个选项框中输入我们需要的项目条件 最后一步创建完毕 创建会在资源解决方案生成如图&#xff1a;

Spark 9:Spark 新特性

Spark 3.0 新特性 Adaptive Query Execution 自适应查询(SparkSQL) 由于缺乏或者不准确的数据统计信息(元数据)和对成本的错误估算(执行计划调度)导致生成的初始执行计划不理想&#xff0c;在Spark3.x版本提供Adaptive Query Execution自适应查询技术&#xff0c;通过在”运行…

小说推文和短剧推广的优势和申请授权方式

小说推文和短剧推广都可以通过”巨量推文“申请授权 先说说优势&#xff0c;短视频赛道有很多&#xff0c;普遍的门槛过高&#xff0c;目前小说推文和短剧推广只要你有短视频账号就可以推广 相对来说门槛更低&#xff0c;可以”白嫖“流量来进行变现

Spring核心源码-如何解决循环依赖

假设有两个类A和B B是A的成员变量&#xff0c;A也是B的成员变量。 假设类A的bean为a&#xff0c;类B的bean为b。且IOC容器先处理A。 熟悉Spring容器初始化的同学&#xff0c;应该都知道&#xff0c;容器初始化的过程中&#xff0c;bean的创建是如下触发的&#xff1a; getBean…

Unity可视化Shader工具ASE介绍——4、ASE的自定义模板使用

大家好&#xff0c;我是阿赵。   继续介绍Unity可视化Shader编辑工具ASE。之前的文章介绍了在ASE里面可以选择不同的Shader类型。这一篇来继续探讨一下&#xff0c;这些Shader类型究竟是什么。 一、所谓的Shader类型是什么 选择不同的Shader类型&#xff0c;会出现不同的选项…

Unity 之 EditorGUILayout.BeginHorizontal/EndHorizontal异常报错问题

报错内容&#xff1a; 缘由&#xff1a;由于在EditorGUILayout.EndHorizontal()之前执行了类似打开窗口的逻辑 解决办法&#xff1a; 在EditorGUILayout.EndHorizontal()之前执行GUIUtility.ExitGUI();