• 10. 正则表达式匹配


    题目中的匹配是一个「逐步匹配」的过程:我们每次从字符串 p 中取出一个字符或者「字符 + 星号」的组合,并在 s 中进行匹配。对于 p 中一个字符而言,它只能在 s 中匹配一个字符,匹配的方法具有唯一性;而对于 p 中字符 + 星号的组合而言,它可以在 s 中匹配任意自然数个字符,并不具有唯一性。因此我们可以考虑使用动态规划,对匹配的方案进行枚举。

    我们用 (f[i][j]) 表示 s 的前 (i) 个字符与 p 中的前 (j) 个字符是否能够匹配。在进行状态转移时,我们考虑 p 的第 (j) 个字符的匹配情况:

    如果 p 的第 (j) 个字符是一个小写字母,那么我们必须在 s 中匹配一个相同的小写字母,即

    [f[i][j] = egin{cases} f[i - 1][j - 1], & s[i] = p[j]\ ext{false}, & s[i] eq p[j] end{cases} ]

    也就是说,如果 s 的第 (i) 个字符与 p 的第 (j) 个字符不相同,那么无法进行匹配;否则我们可以匹配两个字符串的最后一个字符,完整的匹配结果取决于两个字符串前面的部分。

    如果 p 的第 (j)个字符是 *,那么就表示我们可以对 p 的第 (j-1) 个字符匹配任意自然数次。在匹配 (0) 次的情况下,我们有

    [f[i][j]=f[i][j−2] ]

    也就是我们「浪费」了一个字符 + 星号的组合,没有匹配任何 s 中的字符。

    在匹配 (1,2,3, cdots) 次的情况下,类似地我们有

    [egin{aligned} & f[i][j] = f[i - 1][j - 2], quad && ext{if } s[i] = p[j - 1] \ & f[i][j] = f[i - 2][j - 2], quad && ext{if } s[i - 1] = s[i] = p[j - 1] \ & f[i][j] = f[i - 3][j - 2], quad && ext{if } s[i - 2] = s[i - 1] = s[i] = p[j - 1] \ & cdotscdots & end{aligned} ]

    总的转移方程如下:

    [f[i][j] |= egin{cases} f[i][j−2] \ f[i - 1][j - 2] AndAnd s[i] = p[j - 1] \ f[i - 2][j - 2] AndAnd s[i - 1] = s[i] = p[j - 1] \ f[i - 3][j - 2] AndAnd s[i - 2] = s[i - 1] = s[i] = p[j - 1] \ cdotscdots end{cases} ]

    如果我们通过这种方法进行转移,那么我们就需要枚举这个组合到底匹配了 s 中的几个字符,会增导致时间复杂度增加。

    (i - 1)代替上式的(i)得到:

    [f[i-1][j] |= egin{cases} f[i-1][j−2] \ f[i - 2][j - 2] AndAnd s[i-1] = p[j - 1] \ f[i - 3][j - 2] AndAnd s[i - 2] = s[i - 1] = p[j - 1] \ cdotscdots end{cases} ]

    于是转移方程可简化为:

    [f[i][j] |= egin{cases} f[i][j−2] \ f[i - 1][j] AndAnd s[i] = p[j - 1] end{cases} ]

    总的转移方程如下:

    [f[i][j] |= egin{cases} f[i - 1][j - 1] AndAnd s[i] = p[j] & p[j] e '*' \ f[i][j-2] || f[i-1][j] AndAnd s[i] = p[j-1] & p[j] = '*' end{cases} ]

    注意点

    第一层循环(i)下标从(0)开始,因为'*'可以匹配(0)个元素。

    class Solution {
    public:
        bool isMatch(string s, string p) {
            int n = s.size(), m = p.size();
            s = ' ' + s, p = ' ' + p;
            
            vector<vector<int>> f(n + 1, vector<int>(m + 1));
            f[0][0] = true;
            
            auto match = [&](int i, int j) {
                if(i == 0) return false;
                return s[i] == p[j] || p[j] == '.';
            };
            
            for(int i = 0; i <= n; i++)
                for(int j = 1; j <= m; j++)
                    if(p[j] == '*') {
                        f[i][j] |= f[i][j - 2];
                        if(match(i, j - 1))
                            f[i][j] |= f[i - 1][j];
                    }
                    else {
                        if(match(i, j)) 
                            f[i][j] |= f[i - 1][j - 1];
                    }
            
            return f[n][m];
        }
    };
    
  • 相关阅读:
    tcpdump抓localhost 127.0.0.1的包
    fatal: write failure on 'stdout': Bad file descriptor
    rst转html
    Call to WHvSetupPartition failed: ERROR_SUCCESS (Last=0xc000000d/87) (VERR_NEM_VM_CREATE_FAILED)
    error: 'readdir_r' is deprecated [-Werror=deprecated-declarations]
    ubuntu虚拟机设置共享后无权限
    VirtualBox怎么设置从u盘启动,虚拟机从U盘启动
    File类总结
    相对路径的写法
    systeminfo总结
  • 原文地址:https://www.cnblogs.com/fxh0707/p/15016076.html
Copyright © 2020-2023  润新知