1. 程式人生 > >力扣算法題—044通配字符匹配

力扣算法題—044通配字符匹配

遇到 string 失敗 不同 color 循環 遞歸函數 als 檢查

//此為博客講解
//p串中星號的位置很重要,用jStar來表示,還有星號匹配到s串中的位置,
//使用iStart來表示,這裏 iStar 和 jStar 均初始化為 - 1,表示默認情況下是沒有星號的。
//然後再用兩個變量i和j分別指向當前s串和p串中遍歷到的位置。
//
//開始進行匹配,若i小於s串的長度,進行while循環。若當前兩個字符相等,
//或著p中的字符是問號,則i和j分別加1。若p[j] 是星號,那麽我們要記錄星號的位置,
//pStar賦為j,此時j再自增1,iStar賦為i。若當前p[j] 不是星號,並且不能跟p[i] 匹配上,
//那麽此時就要靠星號了,若之前星號沒出現過,那麽就直接跪,比如 s = "aa" 和 p = "c*",

//此時 s[0] 和 p[0] 無法匹配,雖然p[1] 是星號,但還是跪。如果星號之前出現過,可以強行續一波命,
//比如 s = "aa" 和 p = "*c",當發現 s[1] 和 p[1] 無法匹配時,但是好在之前 p[0] 出現了星號,
//我們把 s[1] 交給 p[0] 的星號去匹配。至於如何知道之前有沒有星號,這時就能看出 iStar 的作用了,
//因為其初始化為 - 1,而遇到星號時,其就會被更新為i,那麽我們只要檢測 iStar 的值,
//就能知道是否可以使用星號續命。雖然成功續了命,匹配完了s中的所有字符,但是之後我們還要檢查p串,
//此時沒匹配完的p串裏只能剩星號,不能有其他的字符,將連續的星號過濾掉,如果j不等於p的長度,
//則返回false,參見代碼如下:

 1 class Solution {
 2 public:
 3     bool isMatch(string s, string p) {
 4         int i = 0, j = 0, iStar = -1, jStar = -1;
 5         while (i < s.size()) {
 6             if (s[i] == p[j] || p[j] == ?) {
 7                 ++i; ++j;
 8             }
 9             else
if (p[j] == *) { 10 iStar = i; 11 jStar = j++; 12 } 13 else if (iStar >= 0) { 14 i = ++iStar; 15 j = jStar + 1; 16 } 17 else return false; 18 } 19 while (p[j] == *) ++j; 20 return j == p.size(); 21 } 22 };

//使用動態規劃

 1 class Solution {
 2 public:
 3     bool isMatch(string s, string p) {
 4         int m = s.size(), n = p.size();
 5         vector<vector<bool>> dp(m + 1, vector<bool>(n + 1, false));
 6         dp[0][0] = true;
 7         for (int i = 1; i <= n; ++i) {
 8             if (p[i - 1] == *) dp[0][i] = dp[0][i - 1];
 9         }
10         for (int i = 1; i <= m; ++i) {
11             for (int j = 1; j <= n; ++j) {
12                 if (p[j - 1] == *) {
13                     dp[i][j] = dp[i - 1][j] || dp[i][j - 1];
14                 }
15                 else {
16                     dp[i][j] = (s[i - 1] == p[j - 1] || p[j - 1] == ?) && dp[i - 1][j - 1];
17                 }
18             }
19         }
20         return dp[m][n];
21     }
22 };

//使用遞歸思想
//有三種不同的狀態,返回0表示匹配到了s串的末尾,但是未匹配成功;
//返回1表示未匹配到s串的末尾就失敗了;返回2表示成功匹配。
//那麽只有返回值大於1,才表示成功匹配。至於為何失敗的情況要分類,
//就是為了進行剪枝。在遞歸函數中,若s串和p串都匹配完成了,返回狀態2。
//若s串匹配完成了,但p串但當前字符不是星號,返回狀態0。若s串未匹配完,
//p串匹配完了,返回狀態1。若s串和p串均為匹配完,且當前字符成功匹配的話,
//對下一個位置調用遞歸。否則若p串當前字符是星號,那麽我們首先跳過連續的星號
//。然後我們分別讓星號匹配空串,一個字符,兩個字符,....,直到匹配完整個s串
//,對每種情況分別調用遞歸函數,接下來就是最大的亮點了,也是最有用的剪枝,
//當前返回值為狀態0或者2的時候,返回,否則繼續遍歷。如果我們僅僅是狀態2的時候才返回,
//因為當返回值為狀態0的時候,已經沒有繼續循環下去的必要了,非常重要的一刀剪枝,參見代碼如下:

 1 class Solution {
 2 public:
 3     bool isMatch(string s, string p) {
 4         return helper(s, p, 0, 0) > 1;
 5     }
 6     int helper(string& s, string& p, int i, int j) {
 7         if (i == s.size() && j == p.size()) return 2;
 8         if (i == s.size() && p[j] != *) return 0;
 9         if (j == p.size()) return 1;
10         if (s[i] == p[j] || p[j] == ?) {
11             return helper(s, p, i + 1, j + 1);
12         }
13         if (p[j] == *) {
14             if (j + 1 < p.size() && p[j + 1] == *) {
15                 return helper(s, p, i, j + 1);
16             }
17             for (int k = 0; k <= (int)s.size() - i; ++k) {
18                 int res = helper(s, p, i + k, j + 1);
19                 if (res == 0 || res == 2) return res;
20             }
21         }
22         return 1;
23     }
24 };

力扣算法題—044通配字符匹配