leetcode 10 正则匹配
1. 问题
- 正则表达式匹配
 给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配。
'.' 匹配任意单个字符
'*' 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。
说明:
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。
示例 1:
输入:
s = "aa"
p = "a"
输出: false
解释: "a" 无法匹配 "aa" 整个字符串。
2. 解法
2.1. 递归
这个问题的关键是*号。 从任意处开始,先; 先看第二位是否为 * 号符;如果不是则判断s[0] 是否匹配 p[0],然后向下递归,很简单; 如果p的第二位为 * 号符;那么会有两种可能,*号匹配一次(多次)或者零次; 匹配零次 相当于p的前两位无效,同时不需关心s[0]与p[0]的匹配情况 isMatch(s, p[2:]) 匹配一次 相当于s的第一位被匹配过了 s[0] in [p[0],'.'] and isMatch(s[1:], p) 以上两种情况任意一种满足即为匹配通过 另外需要注意的是边界问题,例如s或p为空。
2.2. 动态规划
转移方程
如果已知 dp[i-1][j-1] 的状态,求dp[i][j]。 第一种情况: s[i] == p[j] or p[j] == '.', dp[i][j] = dp[i-1][j-1] = True 第二种情况: p[j] == '*',这时需要根据前一字符综合判断。 如果p[j-1] != s[i] 说明星号只能匹配0次,所以dp[i][j]=dp[i][j-2] 如果p[j-1]== s[i] or p[j-1] == '.',星号可能匹配0次或1次, 匹配0次时dp[i][j] = dp[i][j-2] 匹配1次时dp[i][j] = dp[i-1][j] 其它情况下均为不匹配,dp[i][j] = False
状态转移方程:

    def isMatch_3_1(self, s, p):
        """
        动态规划
        自顶向下
        :param s:
        :param p:
        :return:
        """
        s_len, p_len = len(s), len(p)
        memo = {}
        def dp(i, j):
            if (i,j) in memo:
                return memo[(i,j)]
            if j == p_len:
                return i == s_len
            first_match = i < s_len and p[j] in {s[i], '.'}
            if j <= p_len - 2 and p[j+1] == '*':
                tmp = dp(i, j+2) or first_match and dp(i+1, j)
            else:
                tmp = first_match and dp(i+1, j+1)
            memo[(i,j)] = tmp
            return tmp
        return dp(0,0)
    def isMatch_3_2(self, s, p):
        """
        动态规划
        自底向上
        :param s:
        :param p:
        :return:
        """
        if not p: return not s
        if not s and len(p) == 1:return False
        s_len, p_len = len(s), len(p)
        dp = [[False for _ in range(p_len + 1)] for _ in range(s_len+1)]
        dp[0][0] = True
        for j in range(2, p_len + 1, 2):
            dp[0][j] = dp[0][j-2] and p[j-1] == '*'
        for i in range(1, s_len + 1):
            for j in range(1, p_len + 1):
                if s[i-1] == p[j-1] or p[j-1] == '.':
                    dp[i][j] = dp[i-1][j-1]
                elif p[j-1] == '*':
                    if p[j-2] == s[i-1] or p[j-2] == '.':
                        dp[i][j] = dp[i][j-2] or dp[i-1][j]
                    else:
                        dp[i][j] = dp[i][j-2]
                else:
                    dp[i][j] = False
        return dp[-1][-1]
3. 附
其实解析也可以反向,leetcode官方提供了一个反向解析的案例,与正向解析类似,同样可以写出状态转移方程,并据此写出代码。
    日拱一卒无有尽,功不唐捐终入海
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号