【算法】leetcode10 Regular Expression Matching

题目: 正则表示匹配

Given an input string (s) and a pattern (p), implement regular expression matching with support for '.'and '*'.

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

示例:

Input1:
s = "aa"
p = "a"
Output1: false
Explanation: "a" does not match the entire string "aa".
Input2:
s = "aa"
p = "a*"
Output2: true
Explanation: '*' means zero or more of the precedeng element, 'a'. Therefore, by repeating 'a' once, it becomes "aa".
Input3:
s = "ab"
p = ".*"
Output3: true
Explanation: ".*" means "zero or more (*) of any character (.)".
Input4:
s = "aab"
p = "c*a*b"
Output4: true
Explanation: c can be repeated 0 times, a can be repeated 1 time. Therefore it matches "aab".
Input5:
s = "mississippi"
p = "mis*is*p*."
Output5: false

      首先在题目理解上,与之前的题(剑指offer)上的不同,“.* " 表示意义上可为任意数,而不一定是单一个数重复,见 input3。

      其次,我们分析题意,可以分成以下几种情况:

1. s 为空,且p为空,表示同时结束,return True;

2. s为空,但p不为空,若想匹配成功,p必然为 “x*” 这类组合,*表示字符 x 个数为0;

3. s不为空,p为空,必然匹配不成功, return False;

4. s不为空,p不为空:

如果p[1]  不等于 “*”,看p[0]和s[0]是否匹配,如果字符相等,或p[0]为 “.”,则后移继续匹配,否则返回False;

如果p[1]  等于 "*",  则表示p[0]可以有0-N个,情况更为复杂一些,还需要看 p[0] 和 s[0] 是否匹配,若不匹配,必为0个,则 p 后移两位; 如果匹配,则说明当前s[0] 匹配成功,将s后移一位,剩余的继续判断。

上述逻辑,就是简单的递归,在写代码时,注意精简即可:

class Solution(object):
    def isMatch(self, s, p):
        """
        :type s: str
        :type p: str
        :rtype: bool
        """
        
        if not p:
            return not s
        
        first_match = bool(s) and p[0] in {"." , s[0]}
        
        if len(p)>=2 and p[1]=="*":
            return self.isMatch(s,p[2:]) or first_match and self.isMatch(s[1:],p)
        else:
            return first_match and self.isMatch(s[1:],p[1:])

          递归方法十分耗时(≈1460ms),所以我们进一步考虑使用动态规划,以空间换时间。思路是一样的,增加了二维数组,存储已经计算的变量,从而极大减少了时间(时间 36 ms)。

class Solution(object):
    def isMatch(self, s, p):
        """
        :type s: str
        :type p: str
        :rtype: bool
        """
        saved = {}
        
        def dp(i,j):
            if (i,j) not in saved:
                if j == len(p):
                    ans = (i == len(s))
                else:
                    first_match = i <len(s) and p[j] in {".",s[i]}
                    if j+1 < len(p) and p[j+1] =="*":
                        ans = dp(i,j+2) or first_match and dp(i+1,j) 
                    else:
                        ans = first_match and dp(i+1,j+1)
                saved[i,j] = ans
            return saved[i,j]
        return dp(0,0)

 

小结

        本题主要难点在理清题目的主要思路,用最精简的方式写出代码。动态规划与递归方法都是基于题目的基本理解。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章