LeetCode: 正则表达式匹配

280 阅读2分钟

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

来源:力扣(LeetCode) 链接:leetcode-cn.com/problems/zh… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

1. 思考

假设待匹配的字符串为s,匹配模式为p。dp[i][j]表示s的前i个字符和p的前j个字符能否匹配。从最简单的情况考虑:
1). 假设模式p中不存在'*',则直接逐字符匹配。即

dp[i][j]={dp[i1][j1],s[i]==s[j]ors[j]==.false,s[i]!=s[j]dp[i][j]= \begin{cases} dp[i-1][j-1], & s[i] == s[j] & or & s[j] == '.' \\ false, & s[i] != s[j] \end{cases}

2). 假设模式p中存在'*',需要考虑'*'匹配几次,

  • 匹配0次,相当于直接去掉匹配模式p中最后两个字符
dp[i][j]=dp[i][j2]dp[i][j]=dp[i][j-2]
  • 匹配1次,相当于s的最后一个字符与匹配模式p的最后两个字符匹配
dp[i][j]=dp[i1][j2]dp[i][j]=dp[i-1][j-2]
  • 匹配2次,相当于s的最后两个字符与匹配模式p的最后两个字符匹配 dp[i][j]=dp[i-2][j-2] 综上所述,匹配1次或多次的时候可以理解为先匹配一次,模式保留,否则枚举所有可能无端增加时间复杂度,并且不利于代码编写。 因此可以分成去掉和保留匹配模式两种情况如下
dp[i][j]={dp[i][j2],s[i]!=s[j1]dp[i][j2]]ordp[i1][j],s[i]==s[j1]dp[i][j]= \begin{cases} dp[i][j-2], & & s[i] != s[j-1] \\ dp[i][j-2]] &or & dp[i-1][j], & s[i] == s[j-1] \end{cases}

因此考虑上述两种情况可得到如下公式:

dp[i][j]={if(s[j]!=){dp[i1][j1],s[i]==s[j]ors[j]==.false,s[i]!=s[j]if(s[j]==){dp[i][j2],s[i]!=s[j1]dp[i][j2]]ordp[i1][j],s[i]==s[j1]dp[i][j]= \begin{cases} if(s[j] != '*') \begin{cases} dp[i-1][j-1], & s[i] == s[j] & or & s[j] == '.' \\ false, & s[i] != s[j] \end{cases}\\ if(s[j] == '*') \begin{cases} dp[i][j-2], & & s[i] != s[j-1] \\ dp[i][j-2]] &or & dp[i-1][j], & s[i] == s[j-1] \end{cases} \end{cases}

2 Coding

bool isMatch(string s, string p)
{
        int m = s.size(), n = p.size();
        vector<vector<bool>> dp(m+1, vector<bool>(n+1, false));
        dp[0][0] = true; // i = 0, j = 0, 匹配

        for (int j = 1; j < n + 1; ++j) // i = 0, j != 0, 根据匹配模式可能匹配如模式'.*','*'匹配0个时匹配
        {
                if (p[j - 1] == '*')
                        dp[0][j] = dp[0][j - 2];
        }
            //j = 0, i != 0时,不匹配
        for (int i = 1; i < m + 1; ++i)
        {
                for (int j = 1; j < n + 1; ++j)
                {
                        if (p[j - 1] != '*')  //情况1
                                dp[i][j] = dp[i - 1][j - 1] && (s[i - 1] == p[j - 1] || p[j - 1] == '.');
                        else   //情况2
                        {
                                
                                dp[i][j] = dp[i][j] || dp[i][j - 2];
                                if(s[i - 1] == p[j - 2] || p[j - 2] == '.')
                                        dp[i][j] = dp[i][j] || dp[i - 1][j];
                        }
                }
        }

        return dp[m][n];
}