C++&Python 描述 LeetCode 10. 正则表达式匹配

Posted 亓官劼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++&Python 描述 LeetCode 10. 正则表达式匹配相关的知识,希望对你有一定的参考价值。

C++&Python 描述 LeetCode 10. 正则表达式匹配

  大家好,我是亓官劼(qí guān jié ),在【亓官劼】公众号、CSDN、GitHub、B站、华为开发者论坛等平台分享一些技术博文。放弃不难,但坚持一定很酷!时光荏苒,未来可期,加油~

  如果喜欢博主的文章可以关注博主的个人公众号【亓官劼】(qí guān jié),如果有需要找博主的话可以在公众号后台留言。建了个小交流群,Q群:545611263,要进微信群的话可以加我V:qiguanjie2015备注拉群即可。
微信公众号关注二维码
  《leetcode刷题系列》,博主将从第一题开始,每天更新当日的刷题情况,每题博主会尽量加一些解题思路的分析和C++&python代码的实现。每日在微信公众号【亓官劼】定时更新,有兴趣一起刷题的小伙伴可以关注公众号来一起卷起来呀。

  同时文章在GitHub中进行了开源,内含本系列文章目前已刷的各个题解和解题思路,GitHub地址为:LeetCode,如果文章对你有帮助的话可以来GitHub点个star,如果有更好的解题思路的话,也可以来GitHub提交~一起改进

题目

给你一个字符串 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
解释:".*" 表示可匹配零个或多个('*')任意字符('.')。

示例 4:

输入:s = "aab" p = "c*a*b"
输出:true
解释:因为 '*' 表示零个或多个,这里 'c' 为 0 个, 'a' 被重复一次。因此可以匹配字符串 "aab"。

示例 5:

输入:s = "mississippi" p = "mis*is*p*."
输出:false

提示:

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

解题思路

DP。由于*.会导致两个串匹配的时候有多种可能性,因此这里可以采用动态规划来进行求解。

状态表示:f(i,j)表示s串中0~jp串中0-j的匹配情况。f(i,j) = true表示匹配,f(i,j) = false表示不匹配

状态转移:

  • p[j] != '*':f(i,j) = f(i-1,j-1) && ( (s[i] == p[j]) || (p[j] == '.') )即在s[0 ~ i-1]

p[0 ~ j-1]匹配的情况下,如果s[i] == p[j]或者p[j] == '.',则匹配。

  • p[j] == '*':f(i,j) = f(i,j-2) || ( f(i-1,j) && (s[i] == p[j-1] || p[j-1] == '.') )即如果s[0 ~ i]p[0 ~ j-2]匹配(当s[i]重复0次的情况) 或者 s[0 ~ i-1]p[ 0 ~ j]匹配并且s[i] == p[j-1](当前一个字串可以匹配,当前重复之前的字符)

算法实现 C++

class Solution {
public:
    bool isMatch(string s, string p) {
        int len1 = s.length(), len2 = p.length();
        vector<vector<bool>> dp(len1+1, vector<bool> (len2+1, false));
        // 在最开始加一个' ',方便解决边界问题
        s = " " + s;
        p = " " + p;
        // 初始化
        dp[0][0] = true;
        for(int j = 2; j <= len2; j++)
            if(p[j] == '*') dp[0][j] = dp[0][j-2];

        for (int i = 1; i <= len1; i++)
            for (int j = 1; j <= len2; j++) {
                if(p[j] != '*'){
                    dp[i][j] = dp[i-1][j-1] && ( (s[i] == p[j]) || p[j] == '.');
                }
                if(p[j] == '*'){
                    if(j >= 2) dp[i][j] = dp[i][j - 2];
                    // 为了防止*复制的情况可以匹配但是被不复制的时候不匹配覆盖掉,所以dp[i][j]和自身进行一次或运算
                    if (s[i] == p[j - 1] || p[j - 1] == '.') dp[i][j] = dp[i-1][j] | dp[i][j];
                }
            }
        return dp[len1][len2];
    }
};

算法实现 python

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        n = s.__len__()
        m = p.__len__()
        dp = [ [False for j in range(m+1) ] for i in range(n+1) ]
        # 在子串前面加一个' ',来方便解决边界问题
        s = ' ' + s
        p = ' ' + p
        # init
        dp[0][0] = True
        for j in range(2, m+1):
            if p[j] == '*': dp[0][j] = dp[0][j-2]

        for i in range(1, n+1):
            for j in range(1, m+1):
                if p[j] != '*': dp[i][j] = dp[i-1][j-1] and ( s[i] == p[j] or p[j] == '.' )
                if p[j] == '*':
                    if j >= 2: dp[i][j] = dp[i][j-2]
                    # 为了防止*复制的情况可以匹配但是被不复制的时候不匹配覆盖掉,所以dp[i][j]和自身进行一次或运算
                    if s[i] == p[j-1] or p[j-1] == '.': dp[i][j] = dp[i][j] or dp[i-1][j]
        return dp[n][m]

以上是关于C++&Python 描述 LeetCode 10. 正则表达式匹配的主要内容,如果未能解决你的问题,请参考以下文章

用队列实现栈

Leetcod6. Z 字形变换(规律题)

C++&Python描述 LeetCode C++&Python描述 LeetCode 165. 比较版本号

C++&Python描述 LeetCode C++&Python描述 LeetCode 剑指 Offer 22. 链表中倒数第k个节点

Bit Manipulation

C++&Python 描述 LeetCode 8. 字符串转换整数 (atoi)