摘要:難度題目給出一個(gè)字符串和一個(gè)要求我們給出這個(gè)字符串是否匹配這個(gè)其中通配符跟我們平常見到的一樣是和代表任意單個(gè)字符代表一個(gè)或多個(gè)字符這個(gè)題跟簡(jiǎn)單正則匹配比較類似可以跟這里面第二個(gè)解法一樣采取類似的動(dòng)態(tài)規(guī)劃解法在里取中間某個(gè)確定的字符串序列將字
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
題目給出一個(gè)字符串和一個(gè)pattern, 要求我們給出這個(gè)字符串是否匹配這個(gè)pattern. 其中通配符跟我們平常見到的一樣, 是 ? 和 * . ?代表任意單個(gè)字符, * 代表一個(gè)或多個(gè)字符.
這個(gè)題跟Leetcode 10 簡(jiǎn)單正則匹配 比較類似, 可以跟這里面第二個(gè)解法一樣, 采取類似的動(dòng)態(tài)規(guī)劃解法, 在pattern里取中間某個(gè)確定的字符串序列, 將字符串和pattern分別切分成兩段再分別判定是否匹配.
例如, 字符串是 abc, 判定是否匹配到*b?, 我們可以抓住中間的b, 匹配到abc中的b, 將abc切分為["a","c"], 將*b?切分為 ["*","?"], 分別判定"a"和"*", 以及"c"和"?"是否匹配, 如果都匹配, 那么整個(gè)最終結(jié)果就是匹配的.
當(dāng)然, 事情有時(shí)候不會(huì)這么順利, 比如字符串出現(xiàn)多個(gè)b呢? 這時(shí)候需要嘗試, pattern中的b到底是字符串中的哪一個(gè)b.
這里提出一種新的, 無遞歸的解法. 基本思路為:
將pattern中所有連續(xù)多個(gè)*置換為單個(gè)*, 比如a**a置換為a*a
跟Leetcode 10 的解法一樣, 將pattern前后都確定的字符去跟輸入字符串前后匹配, 比如字符串a(chǎn)bc和模式a*c, 掐頭去尾變成 b和*, 這期間如果有不同可以直接返回不匹配.
剩下的是有*的部分, 比如pattern可能是*a*bb*c*. 這樣我們采取盡早匹配*之外字符的方式, 像上面那個(gè)pattern, 按順序, 盡早匹配a, bb, 和c, 如果在字符串結(jié)束之前都匹配ok, 這樣最終結(jié)果就是匹配成功的, 否則, 如果某個(gè)子串比如bb找不到, 或者還沒全部匹配完就已經(jīng)走到了字符串的末尾, 都算匹配失敗.
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中包含一部分測(cè)試用例.
這里, 我突然發(fā)現(xiàn), 上面第一步, 將pattern中所有連續(xù)多個(gè)*置換為單個(gè)*, 雖然可以讓pattern變得更簡(jiǎn)單, 但其實(shí)不是非常必要, 既然后面使用游標(biāo), 就可以略過連續(xù)多個(gè)的*. 比如上面接近最后有一句ptnr++, 實(shí)際上就是略過了其后的一個(gè)*, int ptnr=1; 就是略過了開頭的一個(gè)*. 把這些都置換為略過連續(xù)的*, 即可. 改進(jìn)后的程序如下:
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; } }
最終提交結(jié)果速度又快了很多, 在99.49%的提交之前:
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/66531.html
摘要:當(dāng)我們遇到一個(gè)時(shí),因?yàn)橹罂赡芤嘶刂猎撐恢弥匦缕ヅ洌覀円獙⑺南聵?biāo)記錄下來,比如。但是,當(dāng)我們連續(xù)遇到兩次的情況,如何保證我還是能繼續(xù)匹配,而不是每次都退回導(dǎo)致循環(huán)呢所以我們還要記錄一個(gè),用來記錄用上一個(gè)連續(xù)匹配到的中的下標(biāo)。 Wildcard Matching Implement wildcard pattern matching with support for ? and ...
摘要:正則由于的存在,所以有多種狀態(tài),中間狀態(tài)儲(chǔ)存都需要記錄下來。然后以這些狀態(tài)為動(dòng)態(tài)的中轉(zhuǎn),繼續(xù)判斷到最后。最后正則匹配字符串是否成功的判斷依據(jù),就是正則字符串的最大,是否出現(xiàn)在遍歷到最后的狀態(tài)列表中。 題目闡釋: 正則匹配字符串,用程序?qū)崿F(xiàn) 關(guān)鍵理解: 正則匹配,動(dòng)態(tài)規(guī)劃思想,一個(gè)個(gè)向后追溯,后面的依賴前面的匹配成功。 正則和待匹配的字符串長(zhǎng)度不一,統(tǒng)一到正則字符串的index索引上,每...
摘要:題目鏈接這道題還是可以用的方法,用的數(shù)組來解,空間復(fù)雜度較高。和不同,這道題的符號(hào)和前面的沒有關(guān)系,不需要一起考慮。最壞的情況下,間隔出現(xiàn)且每個(gè)都要匹配很多字符,設(shè)一個(gè)平均匹配里面?zhèn)€字符,。其中,是的長(zhǎng)度,是的長(zhǎng)度。 Wildcard Matching 題目鏈接:https://leetcode.com/problems...這道題還是可以用Regular Expression Mat...
摘要:遞歸和動(dòng)規(guī)的方法沒有研究,說一下較為直觀的貪心算法。用和兩個(gè)指針分別標(biāo)記和進(jìn)行比較的位置,當(dāng)遍歷完后,若也遍歷完,說明完全配對(duì)。當(dāng)之前出現(xiàn)過,且此時(shí)和完全無法配對(duì)的時(shí)候,就一起退回在和配對(duì)過的位置。再將和逐個(gè)加繼續(xù)比較,并將后移。 Problem Implement wildcard pattern matching with support for ? and *. ? Matche...
摘要:難度這道題要求我們實(shí)現(xiàn)簡(jiǎn)單的正則表達(dá)式的匹配只要求普通字符的匹配了解正則的同學(xué)都清楚代表任意單個(gè)字符代表個(gè)或多個(gè)前面的字符比如可以匹配到空字符串也可以匹配等等題目還要求我們判定正則是否匹配給定的字符串要判定整個(gè)字符串而不是其中一部分匹配就算 Implement regular expression matching with support for . and *. . Matche...
閱讀 3222·2023-04-25 18:43
閱讀 903·2021-11-24 09:39
閱讀 1367·2021-10-14 09:43
閱讀 3901·2021-09-22 15:58
閱讀 1922·2019-08-29 17:18
閱讀 420·2019-08-29 14:14
閱讀 3086·2019-08-29 13:01
閱讀 1623·2019-08-29 12:33