动态规划学习——通符串匹配,正则表达式

news2025/2/22 6:24:40

目录

​编辑

一,通符串匹配

1.题目

2.题目接口

3,解题思路及其代码

二,正则表达

 1.题目

2.题目接口

3.解题思路及其代码

三,交错字符串

 1.题目

2,题目接口

3.解题思路及其代码


一,通符串匹配

1.题目

给你一个输入字符串 (s) 和一个字符模式 (p) ,请你实现一个支持 '?' 和 '*' 匹配规则的通配符匹配:

  • '?' 可以匹配任何单个字符。
  • '*' 可以匹配任意字符序列(包括空字符序列)。

判定匹配成功的充要条件是:字符模式必须能够 完全匹配 输入字符串(而不是部分匹配)。

 

示例 1:

输入:s = "aa", p = "a"
输出:false
解释:"a" 无法匹配 "aa" 整个字符串。

示例 2:

输入:s = "aa", p = "*"
输出:true
解释:'*' 可以匹配任意字符串。

示例 3:

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

提示:

  • 0 <= s.length, p.length <= 2000
  • s 仅由小写英文字母组成
  • p 仅由小写英文字母、'?' 或 '*' 组成

2.题目接口

class Solution {
public:
    bool isMatch(string s, string p) {

    }
};

3,解题思路及其代码

在做动态规划问题时一般都是按照以下几步来走的:

1.确定状态转移方程

 像这种两个字符串的问题,一般都是定义二维的dp表按照两个字符串的第i和j下标位置来解决问题的。所以在这里定义dp[i][j]表示p在区间[1,j]中的字符是否存在能够匹配s在[1,i]中的字符。

2.状态转移方程

以s的第i个位置,p的第j个位置为研究对象来研究问题。此时分三种情况:1.s[i] == p[j],或者p[j] == '?',在这种情况下dp[i][j] = dp[i-1][j-1]。

2.p[j] == "*",在这种情况下就要看这个*可以顶替掉多少个s中的字符了:

顶替0个:dp[i][j] = dp[i][j-1]

顶替1个:dp[i][j] = dp[i-1][j-1]

顶替2个:dp[i][j] = dp[i-2][j-1]

顶替3个:dp[i][j] = dp[i-3][j-1]......

在以上i种情况下,我们只要找到一个为真便可以了。所以dp[i][j] = dp[i][j-1]||dp[i-1][j-1]||dp[i-2][j-1]||dp[i-3][j-1].....。但是这样表示的话就需要遍历一遍,所以我们必须要优化以上状态表达,优化成为dp[i][j] = dp[i][j-1]||dp[i-1][j]。通过数学推导得知(将dp[i][j-1]后面的表达式转为一个状态表示)。

3.s[i]!=p[j]并且不是以上情况,在这种条件下dp[i][j]直接就是false。

3.初始化

1.在字符串问题里,我们一般会在字符串的开头加上一个' '。

 2.因为*是可以匹配空的,所以当s字符串为空串时p为空串或者p全为*时也是可以匹配的。

初始化如下:

s = ' '+s;
p = ' '+p;

dp[0][0] = true;
//初始化:当我的s是一个空串时,我的p都是*
for(int i = 1;i<n+1;i++) if(dp[0][i-1]&&p[i] == '*') dp[0][i] = true;

4.填表顺序

根据状态转移方程很容易得出dp表的填写顺序是从左到右,从上到下。

5.返回值

 根据状态表示可知返回值是dp[m][n](m表示s的长度,n表示p的长度)    

代码:

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

        vector<vector<bool>>dp(m+1,vector<bool>(n+1));//dp[i][j]表示s,p分别以i,j结尾能不能完全匹配

        s = ' '+s;
        p = ' '+p;

        dp[0][0] = true;
        //初始化:当我的s是一个空串时,我的p都是*
        for(int i = 1;i<n+1;i++) if(dp[0][i-1]&&p[i] == '*') dp[0][i] = true;

        //以i,j为结尾研究问题

        for(int i = 1;i<m+1;i++)
        {
            for(int j = 1;j<n+1;j++)
            {
                //分两种情况
                if(p[j] == s[i]||p[j] == '?')
                {
                    dp[i][j] = dp[i-1][j-1];
                }
                else if(p[j] == '*')
                {
                    //这颗*可以若干个字符,那可以配0个或者无数个得到的状态转移方程如下
                    //如果不匹配dp[i][j] = dp[i][j-1]
                    //如果匹配1个dp[i][j] = dp[i-1][j-1]
                    //如果匹配两个dp[i][j] = dp[i-2][j-1]
                    //.......
                    //在上面的情况中我们只要找到一种便可以
                    //dp[i][j] = dp[i][j-1]||dp[i-1][j-1]||dp[i-2][j-1]||dp[i-3][j-1]......

                    //优化:将上面的i个表达式变成n个表达式表示:dp[i][j] = dp[i][j-1]||dp[i-1][j]       
                     dp[i][j] = dp[i-1][j]||dp[i][j-1];
                    
                }

            }
        } 
        return dp[m][n];

    }
};

二,正则表达

 1.题目

给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配。

  • '.' 匹配任意单个字符
  • '*' 匹配零个或多个前面的那一个元素

所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。

 

示例 1:

输入:s = "aa", p = "a"
输出:false
解释:"a" 无法匹配 "aa" 整个字符串。

示例 2:

输入:s = "aa", p = "a*"
输出:true
解释:因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。

示例 3:

输入:s = "ab", p = ".*"
输出:true
解释:".*" 表示可匹配零个或多个('*')任意字符('.')。

提示:

  • 1 <= s.length <= 20
  • 1 <= p.length <= 20
  • s 只包含从 a-z 的小写字母。
  • p 只包含从 a-z 的小写字母,以及字符 . 和 *
  • 保证每次出现字符 * 时,前面都匹配到有效的字符

2.题目接口

class Solution {
public:
    bool isMatch(string s, string p) {

    }
};

3.解题思路及其代码

但是这道题跟第一道题何其相似啊!!!'.'和'?'匹配规则是一样的,但是注意两个题目的'*'的匹配规则是是不一样的。所以在'*"和初始化处就要稍加改造了,改造如下:

初始化

 for(int i = 2;i<n+1;i+=2) if(dp[0][i-2]&&p[i] == '*') dp[0][i] = true;

当遇到"*"时填表情况如下

                else if(p[j] == '*')
                {
                    //按照题意在*前面一定有字符
                    if(p[j-1] == '.')//无敌匹配
                    {
                        dp[i][j] = dp[i][j-2]||dp[i-1][j];

                    }
                    else//不是.
                    {
                       //判断后再匹配
                       if(p[j-1] == s[i])
                       {
                           dp[i][j] = dp[i][j-2]||dp[i-1][j];
                       }
                       else
                       {
                           dp[i][j] = dp[i][j-2];
                       }
                    }

解题代码如下

class Solution {
public:
    bool isMatch(string s, string p) {

        int m = s.size();
        int n = p.size();

        //经典加上空格
        s = ' '+s;
        p = ' '+p;



        //经典二维dp表
        vector<vector<bool>>dp(m+1,vector<bool>(n+1));

        dp[0][0] = true;

        //初始化:当s为空串时
        for(int i = 2;i<n+1;i+=2) if(dp[0][i-2]&&p[i] == '*') dp[0][i] = true;




        for(int i = 1;i<m+1;i++)
        {
            for(int j = 1;j<n+1;j++)
            {
                //分情况讨论
                if(p[j] == '.'||s[i] == p[j])
                {
                    //i,j位置匹配上了就得看dp[i-1][j-1]
                    dp[i][j] = dp[i-1][j-1];
                }
                else if(p[j] == '*')
                {
                    //按照题意在*前面一定有字符
                    if(p[j-1] == '.')//无敌匹配
                    {
                        dp[i][j] = dp[i][j-2]||dp[i-1][j];

                    }
                    else//不是.
                    {
                       //判断后再匹配
                       if(p[j-1] == s[i])
                       {
                           dp[i][j] = dp[i][j-2]||dp[i-1][j];
                       }
                       else
                       {
                           dp[i][j] = dp[i][j-2];
                       }
                    }
                }
            }
        }


           return dp[m][n];
    }
};

三,交错字符串

 1.题目

给定三个字符串 s1s2s3,请你帮忙验证 s3 是否是由 s1 和 s2 交错 组成的。

两个字符串 s 和 t 交错 的定义与过程如下,其中每个字符串都会被分割成若干 非空 子字符串:

  • s = s1 + s2 + ... + sn
  • t = t1 + t2 + ... + tm
  • |n - m| <= 1
  • 交错 是 s1 + t1 + s2 + t2 + s3 + t3 + ... 或者 t1 + s1 + t2 + s2 + t3 + s3 + ...

注意:a + b 意味着字符串 a 和 b 连接。

示例 1:

输入:s1 = "aabcc", s2 = "dbbca", s3 = "aadbbcbcac"
输出:true

示例 2:

输入:s1 = "aabcc", s2 = "dbbca", s3 = "aadbbbaccc"
输出:false

示例 3:

输入:s1 = "", s2 = "", s3 = ""
输出:true

提示:

  • 0 <= s1.length, s2.length <= 100
  • 0 <= s3.length <= 200
  • s1s2、和 s3 都由小写英文字母组成

进阶:您能否仅使用 O(s2.length) 额外的内存空间来解决它?

2,题目接口

class Solution {
public:
    bool isInterleave(string s1, string s2, string s3) {

    }
};

3.解题思路及其代码

在看到三个字符串时,我就已经犯蒙了。感觉二维的dp表好像已经解决不了问题了,但是其实是可以解决问题的。解决步骤如下:

1,状态表示

仍然是开一个二维dp表dp[][]。仍然以s1的第i个位置和s2的第j个位置为研究对象研究问题。dp[i][j]表示s1的【1,i]区间和s2的【1,j】区间的字符能不能组成s3的【1,i+j】区间的字符。

2.状态转移方程

在这里我们也是分两种情况来讨论:

1,当s1[i] == s3[i+j]时,dp[i][j] = dp[i-1][j]。

2, 当s2[j] == s3[i+j]时,dp[i][j] = dp[i][j-1]。

3, 当以上两种情况都不成立的话,dp[i][j] = false。

所以dp[i][j] = (s1[i]==s3[i+j]&&dp[i-][j])&&(s2[j] == s3[i+j]&&dp[i][j-1])。

3,初始化

为了让下标对应所以得在每个字符的前面加上" "。

  //加上空格,因为空格有意义
   s1 = " "+s1;
   s2 = " "+s2;
   s3 = " "+s3;

当s1和s2都是空串时,能够组成空串

//初始化
dp[0][0] = true;

当有一个串为空时,另一个串要和s3一一匹配

      for(int i =1;i<m+1;i++)//代表s2为空串
        {
            if(s1[i] == s3[i])
            {
                dp[i][0] = true;
            }
            else 
            {
                break;
            }
        }

          for(int i =1;i<n+1;i++)//代表s1为空串
        {
            if(s2[i] == s3[i])
            {
                dp[0][i] = true;
            }
            else
            {
                break;
            }
        }

4,填表顺序

按照状态转移方程可知填表顺序为:从上到下,从左到右。

5,返回值

返回dp[m][n]

代码如下

class Solution {
public:
    bool isInterleave(string s1, string s2, string s3) {

        int m = s1.size();
        int n = s2.size();
        if(m+n!=s3.size()) return false;

        //二维数组表示以i,j位置为结尾能够组成s3的i+j
        vector<vector<bool>>dp(m+1,vector<bool>(n+1));
         
         //加上空格,因为空格有意义
          s1 = " "+s1;
          s2 = " "+s2;
          s3 = " "+s3;

        //初始化
        dp[0][0] = true;

        for(int i =1;i<m+1;i++)//代表s2为空串
        {
            if(s1[i] == s3[i])
            {
                dp[i][0] = true;
            }
            else 
            {
                break;
            }
        }

          for(int i =1;i<n+1;i++)//代表s1为空串
        {
            if(s2[i] == s3[i])
            {
                dp[0][i] = true;
            }
            else
            {
                break;
            }
        }


        //经典以i,j位置为研究对象

        for(int i = 1;i<m+1;i++)
        {
            for(int j = 1;j<n+1;j++)
            {
               dp[i][j] = (s1[i] == s3[i + j] && dp[i - 1][j])
                 || (s2[j] == s3[i + j] && dp[i][j - 1]);
                
                
            }
        }

        return dp[m][n];

    }
};

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

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

相关文章

docker使用详解

介绍 Docker是一个开源的应用容器引擎&#xff0c;让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中&#xff0c;然后发布到任何流行的Linux或Windows操作系统的机器上&#xff0c;也可以实现虚拟化。 Docker基于轻量级虚拟化技术&#xff0c;整个项目基于Go语言开…

2024最新FL Studio21.2MAC电脑版中文版下载安装步骤教程

FL Studio 简称FL&#xff0c;全称Fruity Loops Studio&#xff0c;因此国人习惯叫它"水果"。目前最新版本是FL Studio21.1.1.3750版本&#xff0c;它让你的计算机就像是全功能的录音室&#xff0c;大混音盘&#xff0c;非常先进的制作工具&#xff0c;让你的音乐突破…

MNIST内置手写数字数据集的实现

torchvision库 torchivision库是PyTorch中用来处理图像和视频的一个辅助库&#xff0c;接下来我们就会使用torchvision库加载内置的数据集进行分类模型的演示 为了统一数据加载和处理代码&#xff0c;PyTorch提供了两个类用于处理数据加载&#xff0c;他们分别是torch.utils.…

Typescript中Omit数据类型的理解

在 TypeScript 中&#xff0c;Omit 是一个内置的工具类型&#xff0c;它用于从对象类型中排除指定的属性&#xff0c;并返回剩余的属性。 Omit 的语法如下所示&#xff1a; type Omit<T, K> Pick<T, Exclude<keyof T, K>>;其中&#xff0c;T 表示原始类型…

Leetcode刷题笔记题解(C++):224. 基本计算器

思路&#xff1a; step 1&#xff1a;使用栈辅助处理优先级&#xff0c;默认符号为加号。 step 2&#xff1a;遍历字符串&#xff0c;遇到数字&#xff0c;则将连续的数字字符部分转化为int型数字。 step 3&#xff1a;遇到左括号&#xff0c;则将括号后的部分送入递归&#x…

面向对象三大特征——继承

目录 1. 概述 2. 继承的限制 2.1 单继承 2.2 访问修饰符 2.3 . final 3. 重写 4. super 4.1super的作用 4.2访问父类的成员和被重写方法 4.3调用父类的构造器 1. 概述 多个类中存在相同属性和行为时&#xff0c;将这些内容抽取到单独一个类中&#xff0c;那么就无需在…

DeciLM-7B:突破极限,高效率、高精准度的70亿参数AI模型

引言 在人工智能领域&#xff0c;语言模型的发展速度令人瞩目。Deci团队最近推出了一款具有革命性意义的语言模型——DeciLM-7B。这款模型在速度和精确度上都实现了显著的突破&#xff0c;以其70亿参数的规模&#xff0c;在语言模型的竞争中脱颖而出。 Huggingface模型下载&am…

C# 基本桌面编程(二)

一、前言 本章为C# 基本桌面编程技术的第二节也是最后一节。前一节在下面这个链接 C# 基本桌面编程&#xff08;一&#xff09;https://blog.csdn.net/qq_71897293/article/details/135024535?spm1001.2014.3001.5502 二、控件布局 1 叠放顺序 在WPF当中布局&#xff0c;通…

我与Datawhale的故事之长篇

Datawhale成员 作者&#xff1a;Datawhale团队成员 前 言 上周五周年文章发出后大家反响比较热烈&#xff1a; 我们与Datawhale背后的故事&#xff01; 本期给大家带来三篇长篇回忆 胡锐峰 我与Datawhale的故事 题记&#xff1a;我和你的相遇就像春风拂面&#xff0c;就像夏雨…

[原创][R语言]股票分析实战[2]:周级别涨幅趋势的相关性

[简介] 常用网名: 猪头三 出生日期: 1981.XX.XX QQ联系: 643439947 个人网站: 80x86汇编小站 https://www.x86asm.org 编程生涯: 2001年~至今[共22年] 职业生涯: 20年 开发语言: C/C、80x86ASM、PHP、Perl、Objective-C、Object Pascal、C#、Python 开发工具: Visual Studio、D…

UE5 C++(三)— 基本用法(生命周期、日志、基础变量)

文章目录 生命周期日志打印Outlog打印屏幕打印 基础变量类型FString、FName 和 FText&#xff0c;三者之间的区别 基础数据类型打印 忘记说了每次在Vscode修改后C脚本后&#xff0c;需要编译一下脚本&#xff0c;为了方便我是点击这里编译脚本 生命周期 Actor 生命周期官方文档…

20--Set集合

1、Set集合 1.1 Set集合概述 java.util.Set接口和java.util.List接口一样&#xff0c;同样继承自Collection接口&#xff0c;它与Collection接口中的方法基本一致&#xff0c;并没有对Collection接口进行功能上的扩充&#xff0c;只是比Collection接口更加严格了。与List接口…

wordpress安装之正式开始安装wordpress

1、拉取wordpress镜像 docker pull wordpress 2、启动容器 启动容器&#xff0c;设置容器名为wordpress2并把80端口映射到宿主机的9988端口 docker run -it --name wordpress2 -p 9988:80 -d wordpress 3、查看容器状态 docker ps 4、安装wordpress博客程序 因为我们前面启…

SLAM算法与工程实践——相机篇:传统相机使用(3)

SLAM算法与工程实践系列文章 下面是SLAM算法与工程实践系列文章的总链接&#xff0c;本人发表这个系列的文章链接均收录于此 SLAM算法与工程实践系列文章链接 下面是专栏地址&#xff1a; SLAM算法与工程实践系列专栏 文章目录 SLAM算法与工程实践系列文章SLAM算法与工程实践…

关于找不到XINPUT1_3.dll,无法继续执行代码问题的5种不同解决方法

一、xinput1_3.dll的作用 xinput1_3.dll是Windows操作系统中的一款动态链接库文件&#xff0c;主要用于支持游戏手柄和游戏输入设备。这款文件属于Microsoft Xbox 360兼容性库&#xff0c;它包含了与游戏手柄和其他输入设备相关的功能。在游戏中&#xff0c;xinput1_3.dll负责…

计算机操作系统-第十八天

目录 进程调度时机 补充知识 进程调度的方式 非剥夺调度方式 剥夺调度方式 进程的切换与过程 本节思维导图 进程调度时机 进程调度&#xff08;低级调度&#xff09;&#xff0c;即按照某种算法从就绪队列中选择一个进程为其分配处理机。 共有两种需要进行进程调度与…

CCNP课程实验-OSPF-CFG

目录 实验条件网络拓朴需求 配置实现基础配置1. 配置所有设备的IP地址 实现目标1. 要求按照下列标准配置一个OSPF网络。 路由协议采用OSPF&#xff0c;进程ID为89 &#xff0c;RID为loopback0地址。3. R4/R5/R6相连的三个站点链路OSPF网络类型配置成广播型&#xff0c;其中R5路…

PMP项目管理 - 资源管理

系列文章目录 PMP项目管理 - 质量管理 PMP项目管理 - 采购管理 PMP项目管理 - 资源管理 PMP项目管理 - 风险管理 现在的一切都是为将来的梦想编织翅膀&#xff0c;让梦想在现实中展翅高飞。 Now everything is for the future of dream weaving wings, let the dream fly in…

DISC-MedLLM—中文医疗健康助手

文章目录 DISC-MedLLM 项目介绍数据集构建重构AI医患对话知识图谱生成问答对医学图谱构建图谱生成QA对 人类偏好引导的对话样例其他数据MedMCQA通用数据 模型微调评估评估方式评估结果 总结 DISC-MedLLM 项目介绍 DISC-MedLLM 是一个专门针对医疗健康对话式场景而设计的医疗领…

「斗破年番」小医仙黑皇城遭调戏,五品丹换药材,获取菩提涎消息

Hello,小伙伴们&#xff0c;我是拾荒君。 《斗破苍穹年番》的第75集已经更新了&#xff0c;喜欢这部国漫的小伙伴应该都去观看了吧&#xff0c;拾荒君也是看了看这一集。在这一集中&#xff0c;萧炎成功地帮助吴昊等人摆脱了鹰爪老人的围困&#xff0c;然后便前往了黑皇城。 黑…