LeetCode: 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
首先要弄清楚什么是通配符匹配。需要注意通配符在匹配每一个字符的时候,不需要这个字符之前的匹配结果

这道题可以用回溯法解决。需要回溯的地方是在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;
  }



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值