[Hard]LeetCode第10题——正则表达式匹配

245 阅读1分钟

题目链接

正则表达式匹配

解法——动态规划(O(nm)O(nm)

我们发现本题的字符串匹配可以采取由起点开始逐渐扩大匹配规模的方式,因此可以采用动态规划的状态转移方程求解。

  • 设状态f(i,j)f(i, j)表示字符串s的前ii个字符和字符串p的前jj个字符能否匹配。这里假设sp的下标均从1开始。初始时,f(0,0)=truef(0,0)=true

  • 此时我们回到题目上来。由题意可知在字符串p中,.可以替代任何一个字符;而*可以和前一个字符搭档,让前一个字符的数量变为0或任意多个。注意,当后面一个字符是*的时候,当前字符应该先跳过不处理,与*组成搭档后一并处理。所以我们分为两种情况:

    • 后面一个字符不是*的时候,则当前有f(i,j)=f(i,j)(i=0)(f(i1,j)(i>0)s[i]==p[j]p[j]==.)f(i,j)=f(i,j)(i=0)\lor (f(i-1,j)(i>0)\land s[i] == p[j] \lor p[j] =='.')
    • 当前字符是*的时候,若j2j\ge 2f(i,j)f(i,j)可以从f(i,j2)f(i,j-2)转移,表示丢弃这一次的*和上一个字符;若i>0i>0s[i]=p[j1]s[i]=p[j-1]表示这个字符可以利用这个*,则可以从f(i1,j)f(i-1,j)转移,表示利用*
  • 初始状态为f(0,0)=truef(0,0)=true,循环遍历ii从0到nnjj从1到mm。因为f(0,j)f(0,j)可能是有意义的,需要被转移更新。

  • 最终答案是f(n,m)f(n,m)

代码如下:

class Solution {
public:
    bool isMatch(string s, string p) {
        int n = s.size(), m = p.size();
        s = ' ' + s, p = ' ' + p;
        vector <vector<bool>> f(n + 1, vector<bool>(m + 1)); //相当于新建一个(n, m)的二维数组
        f[0][0] = true;
        for (int i = 0; i <= n; i++)
            for (int j = 1; j <= m; j++) {
                if (j + 1 <= m && p[j + 1] == '*') continue;
                if (i && p[j] != '*') {
                    f[i][j] = f[i - 1][j - 1] && (s[i] == p[j] || p[j] == '.');
                } else if (p[j] == '*') {
                    f[i][j] = f[i][j - 2] || i && f[i - 1][j] && (s[i] == p[j - 1] || p[j - 1] == '.');
                }
            }
        return f[n][m];
    }
};