LeetCode - Regular Expression Matching

LeetCode - Regular Expression Matching

The Problem is described as following:

Implement regular expression matching with support for ‘.‘ and ‘*‘.

‘.‘ Matches any single character.
‘*‘ Matches zero or more of the preceding element.

The matching should cover the entire input string (not partial).

The function prototype should be: bool isMatch(const char *s, const
char *p)

Some examples:

isMatch(“aa”,”a”) → false
isMatch(“aa”,”aa”) → true
isMatch(“aa”, “.*”) → true
isMatch(“ab”, “.*”) → true
isMatch(“aab”, “c*a*b”) → true

整体来说,这道题目具有一定的难度,起初我采用的是递归的解法,但是python写的代码会存在LTE的问题(貌似C++和Java可以AC),遂放弃,转而研究DP的解法,一下对两种方法均做简单说明

递归方法:

针对p的长度分三种情况讨论:

  • len(p)==0时,当且仅当s长度为0输出True;
  • len(p)==1时,当且仅当s长度为1且字符相等(注意p[0]=’.’的情况),输出True;
  • len(p)>1时,需要根据p[1]是否为*,再作区分:
    • p[1]!=’*’ 时,这一情况较为简单,若s[0]!=p[0],输出False,否则字符去掉前一位继续比较;
    • p[1]==’*’,因为不确定星号以及其之前的元素出现次数,就需要针对s中到底有多少位被抵消,分别展开讨论,会带来较大的时间消耗,想必这也就是python代码AC不过的原因,
# Solution version 1
# TLE when input: "baccbbcbcacacbbc", "c*.*b*c*ba*b*b*.a*"
class Solution:
    # @param s, a string
    # @param p, a string
    # @return a boolean
    def isMatch(self, s, p):
        # len == 0
        if len(p) == 0:
            return len(s) == 0
        # len == 1
        if len(p) == 1:
            return (len(s) == 1) and (s[0] == p[0] or p[0] == '.')
        # len > 1 ,next char is '*'
        if p[1] != '*':
            if len(s) == 0:
                return False
            else:
                return (s[0] == p[0] or p[0] == '.') and (self.isMatch(s[1:],p[1:]))
        # next char is '*', more complicated
        while (len(s) > 0) and (s[0] == p[0] or p[0] == '.'):
            if self.isMatch(s, p[2:]):
                return True
            s = s[1:]
        return self.isMatch(s,p[2:])

动态规划:

这一部分思路参考此博客:

思路是使用bool类型的二维数组dp[m+1][n+1](m、n分别为字符串s和p的长度)记录s和p是否匹配,即dp[i+1][j+1]表示s的前i个字符是否与p的前j的字符相匹配。

  • 如果p[j]不等于‘*‘,则dp[i + 1][j + 1] = dp[i][j] && s[i] == p[j]

  • 如果p[j]等于‘*‘,则当且仅当在下面三种情况为真,dp[i + 1][j + 1]为真:

    • ‘*‘前面字符重复出现0次,则p字符串需要往前看2位,即dp[i + 1][j - 1]是否为真

    • ‘*‘前面的字符重复出现1次,则p字符串只需要往前看1位,即dp[i + 1][j]是否为真

    • ‘前面的字符重复出现次数大于1次,则s字符串需要往前看1位,即dp[i][j + 1]是否为真,以及s字符串当前字符(s[i])与p字符串‘‘前面字符(p[j - 1])是否相匹配。

 # Solution Version 2 with DP . AC succeed .
class Solution:
    # @param s, a string
    # @param p, a string
    # @return a boolean
    def isMatch(self, s, p):
        dp = [[False for i in range(len(p)+1)] for j in range(len(s)+1)]
        dp[0][0] = True
        for i in range(1,len(p)+1):
            if p[i-1] == '*' and i >= 2:
                dp[0][i] = dp[0][i-2]
        for i in range(1,len(s)+1):
            for j in range(1,len(p)+1):
                if p[j-1] == '.' or p[j-1] == s[i-1]:
                    dp[i][j] = dp[i-1][j-1]
                elif p[j-1] == '*':
                    dp[i][j] = dp[i][j-2] or dp[i][j-1] or (dp[i-1][j] and (s[i-1] == p[j-2] or p[j-2] == '.'))
        return dp[len(s)][len(p)]

你可能感兴趣的:(LeetCode)