日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

44. Wildcard Matching 通配符匹配

發布時間:2024/5/7 编程问答 51 豆豆
生活随笔 收集整理的這篇文章主要介紹了 44. Wildcard Matching 通配符匹配 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Title

給定一個字符串 (s) 和一個字符模式 § ,實現一個支持 ‘?’ 和 ‘*’ 的通配符匹配。

'?' 可以匹配任何單個字符。 '*' 可以匹配任意字符串(包括空字符串)。

兩個字符串完全匹配才算匹配成功。

說明:

s 可能為空,且只包含從 a-z 的小寫字母。
p 可能為空,且只包含從 a-z 的小寫字母,以及字符 ? 和 *。

示例 1:

輸入:

s = "aa" p = "a"

輸出: false
解釋: “a” 無法匹配 “aa” 整個字符串。

示例 2:

輸入:

s = "aa" p = "*"

輸出: true
解釋: ‘*’ 可以匹配任意字符串。

示例 3:

輸入:

s = "cb" p = "?a"

輸出: false
解釋: ‘?’ 可以匹配 ‘c’, 但第二個 ‘a’ 無法匹配 ‘b’。

示例 4:

輸入:

s = "adceb" p = "*a*b"

輸出: true
解釋: 第一個 ‘’ 可以匹配空字符串, 第二個 '’ 可以匹配字符串 “dce”.

示例 5:

輸入:

s = "acdcb" p = "a*c?b"

輸出: false

動態規劃

Solve

在給定的模式 p 中,只會有三種類型的字符出現:

  • 小寫字母 a?z,可以匹配對應的一個小寫字母;
  • 問號 ?,可以匹配任意一個小寫字母;
  • 星號 *,可以匹配任意字符串,可以為空,也就是匹配零或任意多個小寫字母。

其中「小寫字母」和「問號」的匹配是確定的,而「星號」的匹配是不確定的,因此我們需要枚舉所有的匹配情況。為了減少重復枚舉,我們可以使用動態規劃來解決本題。

我們用 dp[i][j] 表示字符串 s 的前 i 個字符和模式 p 的前 j 個字符是否能匹配。

在進行狀態轉移時,我們可以考慮模式 p 的第 j 個字符 pj,與之對應的是字符串 s 中的第 i 個字符 si

  • 如果 pj 是小寫字母,那么 si 必須也為相同的小寫字母,狀態轉移方程為:dp[i][j]=(si 與 pj 相同)∧dp[i?1][j?1]
  • 如果 pj 是問號,那么對 si 沒有任何要求,狀態轉移方程為:
  • 如果 pj 是星號,那么同樣對 si 沒有任何要求,但是星號可以匹配零或任意多個小寫字母,因此狀態轉移方程分為兩種情況,即使用或不使用這個星號:dp[i][j]=dp[i][j?1]∨dp[i?1][j]

最終的狀態轉移方程如下:

dp[i][j]={(si與pj相同)∧dp[i?1][j?1],pj是小寫字母dp[i?1][j?1],pj是問號dp[i][j?1]∨dp[i?1][j],pj是星號dp[i][j]= \begin{cases} (s_i與p_j相同)∧dp[i?1][j?1], & p_j 是小寫字母 \\ dp[i?1][j?1], & p_j 是問號 \\ dp[i][j?1]∨dp[i?1][j], & p_j 是星號 \end{cases} dp[i][j]=??????(si?pj?)dp[i?1][j?1],dp[i?1][j?1],dp[i][j?1]dp[i?1][j],?pj?pj?pj??

我們也可以將前兩種轉移進行歸納:
dp[i][j]={dp[i?1][j?1],si與pj相同或者pj是問號dp[i][j?1]∨dp[i?1][j],pj是星號False,其它情況dp[i][j]= \begin{cases} dp[i?1][j?1], & s_i與p_j相同或者p_j 是問號 \\ dp[i][j?1]∨dp[i?1][j], & p_j 是星號 \\ False, & 其它情況 \end{cases} dp[i][j]=??????dp[i?1][j?1],dp[i][j?1]dp[i?1][j],False,?si?pj?pj?pj??

細節

只有確定了邊界條件,才能進行動態規劃。在上述的狀態轉移方程中,由于 dp[i][j] 對應著 s 的前 i 個字符和模式 p 的前 j 個字符,因此所有的 dp[0][j] 和 dp[i][0] 都是邊界條件,因為它們涉及到空字符串或者空模式的情況,這是我們在狀態轉移方程中沒有考慮到的:

  • dp[0][0]=True,即當字符串 s 和模式 p 均為空時,匹配成功;

  • dp[i][0]=False,即空模式無法匹配非空字符串;

  • dp[0][j] 需要分情況討論:因為星號才能匹配空字符串,所以只有當模式 p 的前 j 個字符均為星號時,dp[0][j] 才為真。

我們可以發現,dp[i][0] 的值恒為假,dp[0][j] 在 j 大于模式 p 的開頭出現的星號字符個數之后,值也恒為假,而 dp[i][j] 的默認值(其它情況)也為假,因此在對動態規劃的數組初始化時,我們就可以將所有的狀態初始化為False,減少狀態轉移的代碼編寫難度。

最終的答案即為 dp[m][n],其中 m 和 n 分別是字符串 s 和模式 p 的長度。需要注意的是,由于大部分語言中字符串的下標從 0 開始,因此 si 和 pj 分別對應著 s[i?1] 和 p[j?1]。

Code

def isMatch_dp(self, s: str, p: str) -> bool:lengthS, lengthP = len(s), len(p)dp = [[False] * (lengthP + 1) for _ in range(lengthS + 1)]dp[0][0] = Truefor i in range(1, lengthP + 1):if p[i - 1] == '*':dp[0][i] = Trueelse:breakfor i in range(1, lengthS + 1):for j in range(1, lengthP + 1):if p[j - 1] == '*':dp[i][j] = dp[i][j - 1] or dp[i - 1][j]elif p[j - 1] == '?' or s[i - 1] == p[j - 1]:dp[i][j] = dp[i - 1][j - 1]return dp[lengthS][lengthP]

復雜度分析

時間復雜度:O(mn),其中 m 和 n 分別是字符串 s 和模式 p 的長度。

空間復雜度:O(mn),即為存儲所有 (m+1)(n+1) 個狀態需要的空間。此外,在狀態轉移方程中,由于 dp[i][j] 只會從 dp[i][…] 以及 dp[i?1][…] 轉移而來,因此我們可以使用滾動數組對空間進行優化,即用兩個長度為 n+1 的一維數組代替整個二維數組進行狀態轉移,空間復雜度為 O(n)。

總結

以上是生活随笔為你收集整理的44. Wildcard Matching 通配符匹配的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。