您的位置:首页 > 其它

LeetCode: Wildcard Matching (通配符匹配)

2013-04-30 06:00 183 查看
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

首先要弄清楚什么是通配符匹配。需要注意通配符在匹配每一个字符的时候,不需要管这个字符之前的匹配结果。
这道题可以用回溯法解决。需要回溯的地方是在p中遇到一个'*'的时候,我们不能确定需要s中的几个字符去匹配这个'*',所以就进行尝试。首先从一个都不用去匹配,如果不成功就用s中从当前字符去匹配,再不成功就用s中的下一个字符去匹配,一直这样下去,直到成功匹配或者匹配了s中的所有剩余字符。

回溯法的代码:

public boolean isMatch(String s, String p) {
// Start typing your Java solution below
// DO NOT write main() function
if (p.length() == 0) {
return s.length() == 0;
}

if (p.charAt(0) != '*') {
if (s.length() != 0 && (p.charAt(0) == s.charAt(0) || p.charAt(0) == '?')) {
return isMatch(s.substring(1), p.substring(1));
} else {
return false;
}
}

while (s.length() != 0) {
while (p.length() > 1 && p.charAt(1) == '*') {
p = p.substring(1);
}
if (isMatch(s, p.substring(1))) {
return true;
}
s = s.substring(1);
}

return isMatch(s, p.substring(1));
}
这个代码无法通过LeetCode的大集合。尝试使用迭代去解决。

由于通配符匹配的时候,可以看做分段匹配,将p根据‘*’分成不同的部分,把这些部分分别放在s中做字符串匹配,只要能匹配并且各个部分不重叠,那么最终就是匹配的。比如p = abc****d?f*ghi,p可分为三段,abc,
def, ghi。将这三段分别与s进行匹配。

需要注意的地方是第一段和最后一段的匹配。如果第一段的第一个字符不是‘*’,则第一段就需要从第一个字符开始正向进行匹配。如果最后一段的最后一个字符不是‘*’,则最后一段需要从最后一个字符开始反向匹配。

迭代实现的代码很繁琐。

public int stringMatch(String s, String p) {
int sLen = s.length();
int pLen = p.length();
int i = 0;
int j = 0;

for (; i < sLen && j < pLen; i++, j++) {
if (s.charAt(i) != p.charAt(j) && p.charAt(j) != '?') {
i = i - j;
j = -1;
}
}
if (j == pLen) {
return i - j;
} else {
return -1;
}
}

public boolean isMatch(String s, String p) {
// Start typing your Java solution below
// DO NOT write main() function
String matchStr = null;
int first = p.indexOf('*');

if (first == -1) {
// no '*' in the pattern
// s and p must exactly match
return stringMatch(s, p) == 0 && s.length() == p.length();
}

if (first > 0) {
// p does not begin with '*'
// check beginning part of p (before the first '*')
// forward match from the beginning characters of s and p
matchStr = p.substring(0, first);
int i = 0; int j = 0;
for (; i < s.length() && j < matchStr.length(); i++, j++) {
if (s.charAt(i) != matchStr.charAt(j) && matchStr.charAt(j) != '?') {
return false;
}
}
if (j < matchStr.length()) {
return false;
}
// discard matched part in s after matching
s = s.substring(matchStr.length());
}

int last = p.lastIndexOf('*');
if (last < p.length() - 1) {
// p does not end with '*'
// check last part of p (after the very last '*')
// backward match from the last characters of s and p
matchStr = p.substring(last + 1);
int i = s.length() - 1; int j = matchStr.length() - 1;
for (; i >= 0 && j >= 0; i--, j--) {
if (s.charAt(i) != matchStr.charAt(j) && matchStr.charAt(j) != '?') {
return false;
}
}
if (j >= 0) {
return false;
}
// discard matched part in s after matching
s = s.substring(0, s.length() - matchStr.length());
}

// discard matched part in p
p = p.substring(first, last + 1);

// discard consecutive '*' from the front of p
while (p.length() != 0 && p.charAt(0) == '*') {
p = p.substring(1);
}
// discard consecutive '*' from the tail of p
while (p.length() != 0 && p.charAt(p.length() - 1) == '*') {
p = p.substring(0, p.length() - 1);
}

// iteratively match the rest part of p
while (p.length() != 0) {
int star = p.indexOf('*');
if (star != -1) {
matchStr = p.substring(0, star);
} else {
matchStr = p;
}
int match = stringMatch(s, matchStr);
if (match == -1) {
return false;
}
p = p.substring(matchStr.length());
while (p.length() != 0 && p.charAt(0) == '*') {
p = p.substring(1);
}
s = s.substring(match + matchStr.length());
}

return true;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: