摘要:難度題目給出一個字符串和一個要求我們給出這個字符串是否匹配這個其中通配符跟我們平常見到的一樣是和代表任意單個字符代表一個或多個字符這個題跟簡單正則匹配比較類似可以跟這里面第二個解法一樣采取類似的動態規劃解法在里取中間某個確定的字符串序列將字
Implement wildcard pattern matching with support for "?" and "*".
"?" Matches any single character.
"*" Matches any sequence of
characters (including the empty sequence).The matching should cover the entire input string (not partial).
The function prototype should be:
bool isMatch(const char *s,
const char *p)Some examples:
isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "*") → true
isMatch("aa", "a*") → true
isMatch("ab", "?*") → true
isMatch("aab", "c*a*b") → false
難度: Hard
題目給出一個字符串和一個pattern, 要求我們給出這個字符串是否匹配這個pattern. 其中通配符跟我們平常見到的一樣, 是 ? 和 * . ?代表任意單個字符, * 代表一個或多個字符.
這個題跟Leetcode 10 簡單正則匹配 比較類似, 可以跟這里面第二個解法一樣, 采取類似的動態規劃解法, 在pattern里取中間某個確定的字符串序列, 將字符串和pattern分別切分成兩段再分別判定是否匹配.
例如, 字符串是 abc, 判定是否匹配到*b?, 我們可以抓住中間的b, 匹配到abc中的b, 將abc切分為["a","c"], 將*b?切分為 ["*","?"], 分別判定"a"和"*", 以及"c"和"?"是否匹配, 如果都匹配, 那么整個最終結果就是匹配的.
當然, 事情有時候不會這么順利, 比如字符串出現多個b呢? 這時候需要嘗試, pattern中的b到底是字符串中的哪一個b.
這里提出一種新的, 無遞歸的解法. 基本思路為:
將pattern中所有連續多個*置換為單個*, 比如a**a置換為a*a
跟Leetcode 10 的解法一樣, 將pattern前后都確定的字符去跟輸入字符串前后匹配, 比如字符串abc和模式a*c, 掐頭去尾變成 b和*, 這期間如果有不同可以直接返回不匹配.
剩下的是有*的部分, 比如pattern可能是*a*bb*c*. 這樣我們采取盡早匹配*之外字符的方式, 像上面那個pattern, 按順序, 盡早匹配a, bb, 和c, 如果在字符串結束之前都匹配ok, 這樣最終結果就是匹配成功的, 否則, 如果某個子串比如bb找不到, 或者還沒全部匹配完就已經走到了字符串的末尾, 都算匹配失敗.
AC的程序最終可以超越75%的算法, 如下:
public class Solution { public boolean isMatch(String s, String p) { // replace all redundent ** to * if (p.length() > 0) { StringBuffer sb = new StringBuffer(); sb.append(p.charAt(0)); for (int i = 1; i < p.length(); i++) { if (p.charAt(i) != "*" || p.charAt(i - 1) != "*") { sb.append(p.charAt(i)); } } p = sb.toString(); } if (p.length() == 1 && p.charAt(0) == "*") { return true; } int slen = s.length(); int plen = p.length(); int ps = 0; int pp = 0; // trim left non-star element of s and p // "aabb","?*b" -> "abb","*b" while (pp < plen && ps < slen && p.charAt(pp) != "*") { if (p.charAt(pp) != "?" && p.charAt(pp) != s.charAt(ps)) { return false; } pp++; ps++; } int trimleft = pp; s = s.substring(trimleft); p = p.substring(trimleft); // if s and p is not empty // trim right non-star element of s and p // "abb","*b" -> "ab","*" if (s.length() > 0 && p.length() > 0) { slen = s.length(); plen = p.length(); ps = slen - 1; pp = plen - 1; while (pp >= 0 && ps >= 0 && p.charAt(pp) != "*") { if (p.charAt(pp) != "?" && p.charAt(pp) != s.charAt(ps)) { return false; } pp--; ps--; } int trimright = plen - 1 - pp; s = s.substring(0, slen - trimright); p = p.substring(0, plen - trimright); } slen = s.length(); plen = p.length(); // length of s or length of p is zero judgement if (plen == 0) { if (slen > 0) { return false; } else { return true; } } if (slen == 0 && (plen > 1 || plen == 1 && p.charAt(0) != "*")) { return false; } ps = 0; pp = 0; int ptnl = 1; int ptnr = 1; int psl = 0; int psr = 0; // first and last character of p is star // p: *aa*bb* -> (aa,bb) // locate each of the non-star sub-patterns in s sequentially // if all satisfies, return true // otherwise false while (ptnl < plen && ptnr < plen) { // ptnl and ptnr designates left and right index of current // sub-pattern // find a sub-pattern while (p.charAt(ptnr) != "*") { ptnr++; } // find match in s for (int i = psl; i <= slen - (ptnr - ptnl); i++) { int j = ptnl; for (; j < ptnr; j++) { if (s.charAt(i + (j - ptnl)) != p.charAt(j) && p.charAt(j) != "?") { break; } } if (j == ptnr) { // matches current sub-pattern psl = i; psr = psl + (ptnr - ptnl); break; } } if (psl == psr) { // no match for current sub-pattern return false; } // go to next position for next sub-pattern psl = psr; ptnr++; ptnl = ptnr; } return true; } public static void main(String[] args) { Solution s = new Solution(); System.out.println(s.isMatch("bb", "?*?")); System.out.println(s.isMatch("b", "?*?")); System.out.println(s.isMatch("aa", "a")); System.out.println(s.isMatch("aa", "aa")); System.out.println(s.isMatch("aaa", "aa")); System.out.println(s.isMatch("aa", "*")); System.out.println(s.isMatch("aa", "a*")); System.out.println(s.isMatch("ab", "?*")); System.out.println(s.isMatch("aab", "c*a*b")); System.out.println(s.isMatch("aabbaab", "a*b")); System.out.println(s.isMatch("aabbbaaab", "a*b*b")); System.out.println(s.isMatch("aaabababaaabaababbbaaaabbbbbbabbbbabbbabbaabbababab", "*ab***ba**b*b*aaab*b")); System.out.println(s.isMatch("aaabaaaabbbbbbaaabbabbbbababbbaaabbabbabb", "*b*bbb*baa*bba*b*bb*b*a*aab*a*")); System.out.println(s.isMatch( "abbaabbbbababaababababbabbbaaaabbbbaaabbbabaabbbbbabbbbabbabbaaabaaaabbbbbbaaabbabbbbababbbaaabbabbabb", "***b**a*a*b***b*a*b*bbb**baa*bba**b**bb***b*a*aab*a**")); System.out.println(s.isMatch("bbbbbbbabbaabbabbbbaaabbabbabaaabbababbbabbbabaaabaab", "b*b*ab**ba*b**b***bba")); System.out.println(s.isMatch( "abbabaaabbabbaababbabbbbbabbbabbbabaaaaababababbbabababaabbababaabbbbbbaaaabababbbaabbbbaabbbbababababbaabbaababaabbbababababbbbaaabbbbbabaaaabbababbbbaababaabbababbbbbababbbabaaaaaaaabbbbbaabaaababaaaabb", "**aa*****ba*a*bb**aa*ab****a*aaaaaa***a*aaaa**bbabb*b*b**aaaaaaaaa*a********ba*bbb***a*ba*bb*bb**a*b*bb")); } }
main中包含一部分測試用例.
這里, 我突然發現, 上面第一步, 將pattern中所有連續多個*置換為單個*, 雖然可以讓pattern變得更簡單, 但其實不是非常必要, 既然后面使用游標, 就可以略過連續多個的*. 比如上面接近最后有一句ptnr++, 實際上就是略過了其后的一個*, int ptnr=1; 就是略過了開頭的一個*. 把這些都置換為略過連續的*, 即可. 改進后的程序如下:
public class Solution2 { public boolean isMatch(String s, String p) { int slen = s.length(); int plen = p.length(); int ps = 0; int pp = 0; // trim left non-star element of s and p // "aabb","?*b" -> "abb","*b" while (pp < plen && ps < slen && p.charAt(pp) != "*") { if (p.charAt(pp) != "?" && p.charAt(pp) != s.charAt(ps)) { return false; } pp++; ps++; } int trimleft = pp; s = s.substring(trimleft); p = p.substring(trimleft); // if s and p is not empty // trim right non-star element of s and p // "abb","*b" -> "ab","*" slen = s.length(); plen = p.length(); if (slen > 0 && plen > 0) { ps = slen - 1; pp = plen - 1; while (pp >= 0 && ps >= 0 && p.charAt(pp) != "*") { if (p.charAt(pp) != "?" && p.charAt(pp) != s.charAt(ps)) { return false; } pp--; ps--; } int trimright = plen - 1 - pp; s = s.substring(0, slen - trimright); p = p.substring(0, plen - trimright); } slen = s.length(); plen = p.length(); // length of s or length of p is zero judgement if (plen == 0) { if (slen > 0) { return false; } else { return true; } } ps = 0; pp = 0; int ptnl = 0; int ptnr = 0; int psl = 0; int psr = 0; // skip preceding * while (ptnr < plen && p.charAt(ptnr) == "*") { ptnr++; } ptnl = ptnr; // first and last character of p is star // p: *aa*bb* -> (aa,bb) // locate each of the non-star sub-patterns in s sequentially // if all satisfies, return true // otherwise false while (ptnl < plen && ptnr < plen) { // ptnl and ptnr designates left and right index of current // sub-pattern // find a sub-pattern while (ptnr < plen && p.charAt(ptnr) != "*") { ptnr++; } // find match in s for (int i = psl; i <= slen - (ptnr - ptnl); i++) { int j = ptnl; for (; j < ptnr; j++) { if (s.charAt(i + (j - ptnl)) != p.charAt(j) && p.charAt(j) != "?") { break; } } if (j == ptnr) { // matches current sub-pattern psl = i; psr = psl + (ptnr - ptnl); break; } } if (psl == psr) { // no match for current sub-pattern return false; } // go to next position for next sub-pattern psl = psr; while (ptnr < plen && p.charAt(ptnr) == "*") { ptnr++; } ptnl = ptnr; } return true; } }
最終提交結果速度又快了很多, 在99.49%的提交之前:
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/66531.html
摘要:當我們遇到一個時,因為之后可能要退回至該位置重新匹配,我們要將它的下標記錄下來,比如。但是,當我們連續遇到兩次的情況,如何保證我還是能繼續匹配,而不是每次都退回導致循環呢所以我們還要記錄一個,用來記錄用上一個連續匹配到的中的下標。 Wildcard Matching Implement wildcard pattern matching with support for ? and ...
摘要:正則由于的存在,所以有多種狀態,中間狀態儲存都需要記錄下來。然后以這些狀態為動態的中轉,繼續判斷到最后。最后正則匹配字符串是否成功的判斷依據,就是正則字符串的最大,是否出現在遍歷到最后的狀態列表中。 題目闡釋: 正則匹配字符串,用程序實現 關鍵理解: 正則匹配,動態規劃思想,一個個向后追溯,后面的依賴前面的匹配成功。 正則和待匹配的字符串長度不一,統一到正則字符串的index索引上,每...
摘要:題目鏈接這道題還是可以用的方法,用的數組來解,空間復雜度較高。和不同,這道題的符號和前面的沒有關系,不需要一起考慮。最壞的情況下,間隔出現且每個都要匹配很多字符,設一個平均匹配里面個字符,。其中,是的長度,是的長度。 Wildcard Matching 題目鏈接:https://leetcode.com/problems...這道題還是可以用Regular Expression Mat...
摘要:遞歸和動規的方法沒有研究,說一下較為直觀的貪心算法。用和兩個指針分別標記和進行比較的位置,當遍歷完后,若也遍歷完,說明完全配對。當之前出現過,且此時和完全無法配對的時候,就一起退回在和配對過的位置。再將和逐個加繼續比較,并將后移。 Problem Implement wildcard pattern matching with support for ? and *. ? Matche...
摘要:難度這道題要求我們實現簡單的正則表達式的匹配只要求普通字符的匹配了解正則的同學都清楚代表任意單個字符代表個或多個前面的字符比如可以匹配到空字符串也可以匹配等等題目還要求我們判定正則是否匹配給定的字符串要判定整個字符串而不是其中一部分匹配就算 Implement regular expression matching with support for . and *. . Matche...
閱讀 3214·2023-04-25 18:43
閱讀 892·2021-11-24 09:39
閱讀 1361·2021-10-14 09:43
閱讀 3890·2021-09-22 15:58
閱讀 1899·2019-08-29 17:18
閱讀 410·2019-08-29 14:14
閱讀 3078·2019-08-29 13:01
閱讀 1616·2019-08-29 12:33