LeetCode 44. Wildcard Matching(模糊匹配)

原题网址: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 positions = new HashSet<>();
        positions.add(0);
        for(int i=0; i nexts = new HashSet<>();
            Iterator 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 getClosure(Set states) {
        Set closure = new HashSet<>();
        Set currents = new HashSet<>(states);
        while (!currents.isEmpty()) {
            Set 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 states = new HashSet<>();
        states.add(0);
        states = getClosure(states);
        char[] sa = s.toCharArray();
        for(int i=0; i 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。

LeetCode 44. Wildcard Matching(模糊匹配)_第1张图片

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上的位置。

LeetCode 44. Wildcard Matching(模糊匹配)_第2张图片

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;
    }
}

另一种实现,思路比较乱:

public class Solution {
    public boolean isMatch(String s, String p) {
        char[] sa = s.toCharArray();
        char[] pa = p.toCharArray();
        int i=0, j=0;
        int lastI=-1, lastJ=-1;
        while (i0 && pa[j-1] == '*');
    }
}


你可能感兴趣的:(匹配,正则表达式,模糊,wildcard,广度优先搜索,动态规划,贪心算法)