10. 正则表达式匹配

10. 正则表达式匹配

题目描述

给你一个字符串 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 . l e n g t h ≤ 20 0 \le s.length \le 20 0s.length20

  • 0 ≤ p . l e n g t h ≤ 30 0 \le p.length \le 30 0p.length30

  • s 可能为空,且只包含从 a-z 的小写字母。

  • p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。

  • 保证每次出现字符 * 时,前面都匹配到有效的字符


题解:

动态规划。

f [ i ] [ j ] f[i][j] f[i][j] 表示 s [ 0.. i ) s[0..i) s[0..i) p [ 0... j ) p[0...j) p[0...j) 是否匹配,状态转移如下:

  • 若 p[j - 1] != ‘*’:

    1. 若 p[j - 1] == ‘.’,万能匹配符, f [ i ] [ j ] = f [ i − 1 ] [ j − 1 ] f[i][j] = f[i - 1][j - 1] f[i][j]=f[i1][j1]
    2. 若 p[j - 1] == s[i - 1] ,同样的, f [ i ] [ j ] = f [ i − 1 ] [ j − 1 ] f[i][j] = f[i - 1][j - 1] f[i][j]=f[i1][j1]
  • 若 p[j - 1] == ‘*’:

    这种情况下,需要根据 ‘*’ 前面的字符重复几次来判断

    1. 重复 0 次,这种情况分为两种:

      • 一是 p[j - 2] 与 s[i - 1] 根本不匹配,那么 p[j - 2] 和 p[j - 1] 可以忽略不计, f [ i ] [ j ] = f [ i ] [ j − 2 ] f[i][j] = f[i][j - 2] f[i][j]=f[i][j2]
      • 二是 p[j - 2] 与 s[i - 1] 匹配,但是不想让 p[j - 2] 和 s[i - 1] 匹配,那么 f [ i ] [ j ] = f [ i ] [ j − 2 ] f[i][j] = f[i][j - 2] f[i][j]=f[i][j2]
    2. 重复多次,如果我们考虑重复多少次的话,这样的话,我们需要枚举次数:

      f [ i ] [ j ] = f [ i − 1 ] [ j − 2 ] ( s [ i − 1 ] = p [ j − 2 ] ) f[i][j] = f[i - 1][j - 2](s[i - 1] = p[j - 2]) f[i][j]=f[i1][j2](s[i1]=p[j2])

      f [ i ] [ j ] = f [ i − 2 ] [ j − 2 ] ( s [ i − 2 ] = s [ i − 1 ] = p [ j − 2 ] ) f[i][j] = f[i - 2][j - 2](s[i - 2] = s[i - 1] = p[j - 2]) f[i][j]=f[i2][j2](s[i2]=s[i1]=p[j2])

      f [ i ] [ j ] = f [ i − k ] [ j − 2 ] ( s [ i − k ] = s [ i − k + 1 ] = . . . = s [ i − 1 ] = p [ j − 2 ] f[i][j] = f[i - k][j - 2](s[i - k] = s[i - k + 1] = ... = s[i - 1] = p[j - 2] f[i][j]=f[ik][j2](s[ik]=s[ik+1]=...=s[i1]=p[j2])

      这样会增加一层枚举的时间复杂度。。。

      我们可以换个方向考虑,假设已经匹配 s[i - 1] ,将 s[i - 1] 扔掉,用 ‘p[j - 2]*’ 这个组合继续匹配下去,那么: f [ i ] [ j ] = f [ i − 1 ] [ j ] f[i][j] = f[i - 1][j] f[i][j]=f[i1][j] ,而在求 f [ i − 1 ] [ j ] f[i - 1][j] f[i1][j] 的过程中包含了上述枚举的状态,不会漏掉某个状态。

不管怎么考虑,时间复杂度是: O ( n ∗ m ) O(n*m) O(nm),而空间复杂度需要看具体写法。

代码一:

空间复杂度: O ( n ∗ m ) O(n * m) O(nm)

class Solution {
public:
    bool isMatch(string s, string p) {
        int lens = s.length();
        int lenp = p.length();
        if ( !lens && !lenp ) return true;
        vector<vector<bool>> f( lens + 1, vector<bool>( lenp + 1, false ) );
        f[0][0] = true;
        for ( int i = 0; i <= lens; ++i ) {
            for ( int j = 1; j <= lenp; ++j ) {
                if ( p[j - 1] != '*' ) {
                    if ( i && (s[i - 1] == p[j - 1] || p[j - 1] == '.') )
                        f[i][j] = f[i - 1][j - 1];
                } else {
                    if ( j > 1 && f[i][j - 2] ) f[i][j] = true;
                    else if ( i && j > 1 && ( p[j - 2] == '.' || s[i - 1] == p[j - 2] ) )
                        f[i][j] = f[i - 1][j];
                }
            }
        }
        return f[lens][lenp];
    }
};
/*
时间:12ms,击败:59.53%
内存:7.2MB,击败:50.44%
*/

代码二:

空间复杂度: O ( m ) O(m) O(m),使用滚动数组优化。

class Solution {
public:
    bool isMatch(string s, string p) {
        int lens = s.length();
        int lenp = p.length();
        if ( !lens && !lenp ) return true;
        vector<bool> f(lenp + 1, false), t;
        f[0] = true;
        for ( int i = 0; i <= lens; ++i ) {
            if ( i ) fill( f.begin(), f.end(), false );
            for ( int j = 1; j <= lenp; ++j ) {
                if (p[j - 1] == '*' ) {
                    if ( j > 1 && f[j - 2] ) f[j] = true;
                    else if ( i && j > 1 && ( p[j - 2] == '.' || s[i - 1] == p[j - 2] ) )
                        f[j] = t[j];
                } else {
                    if ( i && (s[i - 1] == p[j - 1] || p[j - 1] == '.') )
                        f[j] = t[j - 1];
                }
            }
            t = f;
        }
        return f[lenp];
    }
};
/*
时间:12ms,击败:59.53%
内存:6.5MB,击败:92.34%
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值