【算法】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)

 

小結

        本題主要難點在理清題目的主要思路,用最精簡的方式寫出代碼。動態規劃與遞歸方法都是基於題目的基本理解。

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