Given an input string (s
) and a pattern (p
), implement wildcard pattern matching with support for '?'
and '*'
.
1 |
|
The matching should cover the entire input string (not partial).
Note:
s
could be empty and contains only lowercase lettersa-z
.p
could be empty and contains only lowercase lettersa-z
, and characters like?
or*
.
Example 1:
1 |
|
Example 2:
1 |
|
Example 3:
1 |
|
Example 4:
1 |
|
Example 5:
1 |
|
Related Topics:String
、Backtracking
、Dynamic Programming
、Greedy
解題邏輯與實作
有點像是第十題的 Regular Expression Matching,不過符號的意義不太一樣,這邊使用的 ?
表示一個萬用字元, *
則是表示多個萬用字元。
遞迴
跟 Regular Expression 相比最大的差異應該是 *
的用法。在 Regular Expression 中 *
不可能單獨存在,必定會跟跟在某個字元後面,在產生 subpattern 時要特別注意;但在這題中 *
可以單獨存在,subpatter 應該只有 pattern 或 pattern[1:] 兩種。
- 若 pattern 為空字串,則檢查 string 是否為空字串
- 是,則回傳 True
- 否,則回傳 False
- 檢查 string 是否為空字串
- 是,判斷 pattern 是否為
*
- 是,呼叫遞迴傳入 string 與 pattern[1:]
- 否,則回傳 False
- 否,向下執行
- 是,判斷 pattern 是否為
- pattern 的字首與 string 的字首是否匹配(匹配情況包含 pattern 字首為
?
與*
的情況)- 是,判斷 pattern 是否為
*
- 是,則呼叫遞迴傳入分別傳入 string[1:] 與 pattern 和 string[1:] 與 pattern[1:]
- 否,則呼叫遞迴傳入 string[1:] 與 pattern[1:]
- 否,則回傳 False
- 是,判斷 pattern 是否為
一樣多加了參數暫存比較結果,節省呼叫次數。不過按照上面那個邏輯去寫在遇到這個 testcase 時會 Memory Limit Exceeded,所以修改了第二個判斷式的邏輯,判斷 pattern 扣除掉 *
長度:
- 若 pattern 扣除掉
*
長度為 0,則回傳 True- 代表 pattern 剩下的整句都是
*
,因此不用管 string 內容是什麼一定會匹配。
- 代表 pattern 剩下的整句都是
- 若 pattern 扣除掉
*
長度大於 string 的長度,則回傳 False- 也就是即便
*
全用來匹配空字串,仍會有部分 pattern 無法匹配上 string,因為除*
外的 pattern 符號都必須匹配一個字元,但目前 pattern 比 string 還長… - 另外 string 長度等於 0 的 case,也包含在這,因此原先判斷式中對於 string 長度為 0 的 case 可以全刪除了。
- 也就是即便
1 |
|
總算可以過了,但說實話效能不是很好,跑出了 1096 ms、40.91 %的成績,還有非常大的改進空間。
雙指標
原本是在找 Dynamic Programming 的解法,但連續找到兩篇說用 DP 會 TLE,說要改用雙指標回溯,所以我決定也來寫寫看:
- 初始化兩個指標 s_index 與 p_index,分別指向 string 與 pattern 的字首
- 判斷 s_index 是否小於 string 長度
- 是
- 若指標位置可以匹配(匹配情況包含 pattern 為
?
,但排除為*
的情況),兩個指標皆向後移動 - 若 pattern 目前指向為
*
,則 pattern 指標向後移動,並記下目前指標位置(last_s_index 與 last_p_index)- 先假設
*
匹配的是空字元的情況,向後進行匹配,
- 先假設
- 假設
*
匹配空字元狀況下,無法完成整句匹配,因此所記錄的位置,且 last_s_index 加一- 表示它匹配了
*
,因此可以不再考慮
- 表示它匹配了
- 若上述的 Case 皆無法匹配,則為回傳 False
- 若指標位置可以匹配(匹配情況包含 pattern 為
- 否,向下執行
- 是
- 在掃完 string 後,檢查 pattern 是否還有剩下除
*
外的字元- 有,表示未完成匹配,回傳 False
- 無,則回傳 True
1 |
|
效能好上不少,136 ms、 83.93%
Dynamic Programming & Greedy Algorithm
是說看標籤應該還可以用 Dynamic Programming 跟 Greedy Algorithm 來解題,先欠著回頭再來研究 XD