用动态规划解决通配符匹配字符串问题

leetcode上这个题目出现了两次,基本都是要求答题者写代码完成 '*' 和 '?' 通配符的匹配。
一下摘录其中一题:

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为空时。
    然后考虑一般情况,也分两种情况讨论:
  • p 开头为 '*',若开头为星号,接下来有三种匹配方式:
    • p[0] 仅匹配单个字符 s[0],p[1] ~ p[m] 匹配 s[1] ~ s[n],此时递归调用 isMatch(s.substr(1,s.size() - 1), p.substr(1,p.size() - 1))
    • p[0] 匹配字符串 s[0] ~ s[i],此时递归调用isMatch(s.substr(1,s.size() - 1), p.substr(0,p.size() ))
    • p[0]匹配空字符串,此时递归调用isMatch(s.substr(0,s.size() ), p.substr(1,p.size() - 1))
  • p 开头不为 '*',如果p[0] 与 s[0]匹配,此时递归调用 isMatch(s.substr(1,s.size() - 1), p.substr(1,p.size() - 1)),否则匹配失败。
    将以上思路写成代码如下:
    class Solution {
    public:
      bool isMatch(string s, string p) {
          if(p.size() == 0) {
              if(s.size() == 0)
              return true;
              return false;
          }
          if(s.size() == 0) {
              if(p[0] == '*')
                  return isMatch(s.substr(0,s.size()), p.substr(1,p.size() - 1));
              return false;
          }
          bool res;
          if(p[0] == '*') {
              res = isMatch(s.substr(1,s.size() - 1), p.substr(1,p.size() - 1)) || 
              isMatch(s.substr(1,s.size() - 1), p.substr(0,p.size())) || 
              isMatch(s.substr(0,s.size()), p.substr(1,p.size() - 1));
          }
          else {
              if(p[0] == s[0] || p[0] == '?')
                  res = isMatch(s.substr(1,s.size() - 1), p.substr(1,p.size() - 1));
              else
                  return false;
          }
          return res;
      }
    };
    但是,递归的思路解法速度不够,再leetcode上会超时,那么就需要我们用动态规划解决。
    同样的道理,根据上述递归的思路写出递推关系式
    P[i][j] = P[i - 1][j - 1] && (s[i - 1] == p[j - 1] || p[j - 1] == '?'), if p[j - 1] != '*';
    P[i][j] = P[i][j - 1] || P[i - 1][j], if p[j - 1] == '*'.
    依据上述关系,可以写出新的代码,代码如下:
    class Solution {
    public:
      bool isMatch(string s, string p) { 
          int m = s.length(), n = p.length();
          vector<bool> cur(m + 1, false); 
          cur[0] = true;
          for (int j = 1; j <= n; j++) {
              bool pre = cur[0]; // use the value before update
              cur[0] = cur[0] && p[j - 1] == '*'; 
              for (int i = 1; i <= m; i++) {
                  bool temp = cur[i]; // record the value before update
                  if (p[j - 1] != '*')
                      cur[i] = pre && (s[i - 1] == p[j - 1] || p[j - 1] == '?');
                  else cur[i] = cur[i - 1] || cur[i];
                  pre = temp;
              }
          }
          return cur[m]; 
      }
    };

转载于:https://my.oschina.net/ZhangShurong/blog/994227

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值