您的位置:首页 > 其它

LeetCode 44. Wildcard Matching(模糊匹配)

2016-05-21 04:07 531 查看
原题网址:https://leetcode.com/problems/wildcard-matching/

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

方法一:广度优先搜索。

public class Solution {
public boolean isMatch(String s, String p) {
Set<Integer> positions = new HashSet<>();
positions.add(0);
for(int i=0; i<p.length(); i++) {
Set<Integer> nexts = new HashSet<>();
Iterator<Integer> it = positions.iterator();
while (it.hasNext()) {
Integer pos = it.next();
if (p.charAt(i) == '*') {
for(int j=pos; j<=s.length(); j++) nexts.add(j);
} else if (p.charAt(i) == '?') {
nexts.add(pos+1);
} else {
if (pos < s.length() && s.charAt(pos) == p.charAt(i)) {
nexts.add(pos+1);
}
}
}
positions = nexts;
}
return positions.contains(s.length());
}
}


方法二:非确定状态自动机,广度优先搜索。

public class Solution {
// pattern,直接通过pattern计算自动机的状态转移
private char[] pa;
// 扣除*号之后距离目标的最短距离,如果没有考虑距离会超时。
private int[] distance;
private void buildSimpleNFA(String p) {
pa = p.toCharArray();
int count = 0;
distance = new int[pa.length+1];
for(int i=pa.length-1; i>=0; i--) {
if (pa[i] == '*') distance[i] = count;
else distance[i] = ++ count;
}
}
private Set<Integer> getClosure(Set<Integer> states) {
Set<Integer> closure = new HashSet<>();
Set<Integer> currents = new HashSet<>(states);
while (!currents.isEmpty()) {
Set<Integer> nexts = new HashSet<>();
for(int state: currents) {
closure.add(state);
if (state < pa.length && pa[state] == '*') nexts.add(state+1);
}
currents = nexts;
}
return closure;
}
public boolean isMatch(String s, String p) {
buildSimpleNFA(p);
Set<Integer> states = new HashSet<>();
states.add(0);
states = getClosure(states);
char[] sa = s.toCharArray();
for(int i=0; i<sa.length; i++) {
Set<Integer> nexts = new HashSet<>();
for(int state: states) {
if (state>=pa.length || i+distance[state]>sa.length) continue;
if (pa[state] == '*') nexts.add(state);
if (pa[state] == '*' || pa[state] == '?' || pa[state] == sa[i]) nexts.add(state+1);
}
states = getClosure(nexts);
}
return states.contains(pa.length);
}
}


方法三:动态规划,外层循环为pattern。



public class Solution {
public boolean isMatch(String s, String p) {
if (s == null && p == null) return true;
if (s == null || p == null) return false;
char[] sa = s.toCharArray();
char[] pa = p.toCharArray();
// matched[i][j]表示是否成功匹配到p的第i个(不含)和s的第j个(不含)
boolean[][] matched = new boolean[pa.length+1][sa.length+1];
matched[0][0] = true;
for(int i=1; i<=pa.length; i++) {
matched[i][0] = pa[i-1] == '*' && matched[i-1][0];
for(int j=1; j<=sa.length; j++) {
if (pa[i-1] == '*') matched[i][j] = matched[i][j-1] || matched[i-1][j];
else if (pa[i-1] == '?') matched[i][j] = matched[i-1][j-1];
else if (pa[i-1] == sa[j-1]) matched[i][j] = matched[i-1][j-1];
}
}
return matched[pa.length][sa.length];
}
}


方法四:动态规划,外层循环为s

public class Solution {
public boolean isMatch(String s, String p) {
if (s.length()==0 && p.length()==0) return true;
if (p.length()==0) return false;
char[] sa = s.toCharArray();
char[] pa = p.toCharArray();
boolean[][] matched = new boolean[sa.length+1][pa.length+1];
matched[0][0] = true;
for(int j=1; j<=pa.length; j++) {
if (pa[j-1]=='*') matched[0][j] = matched[0][j-1];
}
for(int i=1; i<=sa.length; i++) {
matched[i][0] = pa[0] == '*' && matched[i-1][0];
for(int j=1; j<=pa.length; j++) {
if (pa[j-1] == '*') matched[i][j] = matched[i-1][j] || matched[i][j-1];
else if (pa[j-1] == '?') matched[i][j] = matched[i-1][j-1];
else if (pa[j-1] == sa[i-1]) matched[i][j] = matched[i-1][j-1];
}
}
return matched[sa.length][pa.length];
}
}


方法五:贪心法,总是假定星号不匹配,后续匹配不成功才使用星号,因此非星号总是被优先消耗掉。保存最近一个星号的位置,以及该星号所匹配到的s上的位置。



public class Solution {
public boolean isMatch(String s, String p) {
char[] sa = s.toCharArray();
char[] pa = p.toCharArray();
int si = 0, pi = 0;
// ls表示最近一个星号匹配到的s的位置
// lp表示最近一个星号的位置
int ls = -1, lp = -1;
while (si < sa.length) {
if (pi < pa.length && (pa[pi] == '?' || sa[si] == pa[pi])) {
si ++;
pi ++;
} else if (pi < pa.length && pa[pi] == '*') {
ls = si;
lp = pi ++;
} else if (ls >= 0) {
si = ++ ls;
pi = lp + 1;
} else {
return false;
}
}
while (pi < pa.length && pa[pi] == '*') pi ++;
return pi == pa.length;
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: