剑指 Offer 19. 正则表达式匹配

剑指 Offer 19. 正则表达式匹配

题目

请实现一个函数用来匹配包含'. '和''的正则表达式。模式中的字符'.'表示任意一个字符,而''表示它前面的字符可以出现任意次(含0次)。在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但与"aa.a"和"ab*a"均不匹配。

示例 1:

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

思路

这里为了好理解假设 s 和 p 的索引都是从1开始的

注意:s的长度一定要从0开始枚举,因为p有可能会匹配空字符串

  • 状态:设 f[i][j] 表示 s 的前 i 个字符 和 p 的前 j 个字符是否匹配
  • 转移
    • p[j] 为普通字符或 .
      • f[i][j] = f[i-1][j-1] (s[i] == p[j] || p[j] == '.')
      • f[i][j] = false (s[i] != p[j])
    • p[j]*
      • 星号前字符重复0次:f[i][j] = f[i][j-2]
      • 星号前字符重复1次:f[i][j] = f[i-1][j-2], (s[i] == p[j-1])
      • 星号前字符重复2次:f[i][j] = f[i-3][j-2], (s[i]==s[i-1]==p[j-1])
      • ...
  • 优化:对于p[j]*的情况,我们要枚举这个组合到底匹配了 s 中的几个字符
    • f[i][j] = f[i-1][j] (s[i] == p[j-1])
    • f[i][j] = f[i][j-2] (s[i] != p[j-1])

代码

class Solution {
public:
    bool isMatch(string s, string p) {
        int m = s.size();
        int n = p.size();
        auto matches = [&](int i, int j) {
            if (i == 0) {
                return false;
            }
            if (p[j-1] == '.') {
                return true;
            }
            return s[i-1] == p[j-1];
        };

        int f[m+1][n+1];
        memset(f, 0, sizeof(f));
        f[0][0] = true;
        for (int i = 0; i <= m; ++i) { // 外层循环一定要是原始字符串(好像也不一定?)
            for (int j = 1; j <= n; ++j) {
                if (p[j-1] == '*') {
                    f[i][j] |= f[i][j-2]; // 相当于重复 0 次
                    if (matches(i, j-1)) { // 重复 n 次
                        f[i][j] |= f[i-1][j];
                    }
                }
                else {
                    if (matches(i, j)) {
                        f[i][j] |= f[i-1][j-1];
                    }
                }
            }
        }
        return f[m][n];
    }

};
posted @ 2022-05-23 10:38  沐灵_hh  阅读(21)  评论(0编辑  收藏  举报