通配符匹配

146 阅读1分钟

leetcode44 通配符匹配

描述

给定一个字符串 (s) 和一个字符模式 (p) ,实现一个支持 '?' 和 '*' 的通配符匹配。

思路-动态规划

  • 对规则进行处理,比如多个*进行合并等
  • 逐条进行匹配
    • 所有规则匹配完后,如果通过返回true
    • 如果规则是字符串,直接匹配固定长度字符串
    • 如果是rule【number,boolean】
      • 如果rule[1]=true,匹配固定长度字符
      • 如果rule[1]=false,说明有*,可以递归匹配
      • 并通过动态规划,记录规则,对应那些字符串位置不能匹配成功

效率

企业微信截图_1651829863909.png

代码如下

function isMatch(s: string, p: string): boolean {
  const dp = [];
  const rules = getRules(p);
  return volidStr(s, rules, 0, 0);

  function getRules(p: string) {
    const rules = [];
    let i = 0,
      j = 0;
    while (i < p.length) {
      const preChar = p.charAt(i);
      j = i + 1;
      if (preChar !== "*" && preChar !== "?") {
        while (j < p.length) {
          const nextChar = p.charAt(j);
          if (nextChar !== "*" && nextChar !== "?") {
            j++;
          } else {
            break;
          }
        }
        rules.push(p.substring(i, j));
        i = j;
      } else {
        const temp: [number, boolean?] = preChar === "*" ? [0] : [1, true];
        while (j < p.length) {
          const nextChar = p.charAt(j);
          if (nextChar !== "*" && nextChar !== "?") {
            break;
          }
          if (nextChar === "*" && temp[1]) {
            temp[1] = false;
          } else if (nextChar === "?") {
            temp[0] = temp[0] + 1;
          }
          j++;
        }
        rules.push(temp);
        i = j;
      }
    }
    return rules;
  }

  function volidStr(str: string, rules, i: number, j: number): boolean {
    if (
      i === rules.length &&
      (j === str.length ||
        (j < str.length && Array.isArray(rules[i - 1]) && !rules[i - 1][1]))
    ) {
      return true;
    } else if (i === rules.length) {
      return false;
    } else {
      const rule = rules[i];
      //通配符之类的
      if (Array.isArray(rule)) {
        return volidStr(str, rules, i + 1, j + rule[0]);
      } else {
        const preRule = rules[i - 1];
        if (Array.isArray(preRule) && !preRule[1]) {
          let index = str.indexOf(rule, j);
          while (index >= 0) {
            if (!dp[i + 1]) {
              dp[i + 1] = [];
            }
            dp[i + 1][rule.length + index] =
              dp[i + 1][rule.length + index] === undefined
                ? volidStr(str, rules, i + 1, rule.length + index)
                : dp[i + 1][rule.length + index];
            if (!dp[i + 1][rule.length + index]) {
              index = str.indexOf(rule, index + 1);
            } else {
              return true;
            }
          }
          return false;
        } else {
          if (str.substring(j, rule.length + j) === rule) {
            return volidStr(str, rules, i + 1, rule.length + j);
          } else {
            return false;
          }
        }
      }
    }
  }
}

const cases: [string, string][] = [
  ["ab", "*a"],
  ["", "?"],
  ["aa", "a"],
  ["bbbab", "*??a?"],
  ["abcabczzzde", "*abc???de*"],
  [
    "abbabaaabbabbaababbabbbbbabbbabbbabaaaaababababbbabababaabbababaabbbbbbaaaabababbbaabbbbaabbbbababababbaabbaababaabbbababababbbbaaabbbbbabaaaabbababbbbaababaabbababbbbbababbbabaaaaaaaabbbbbaabaaababaaaabb",
    "**aa*****ba*a*bb**aa*ab****a*aaaaaa***a*aaaa**bbabb*b*b**aaaaaaaaa*a********ba*bbb***a*ba*bb*bb**a*b*bb",
  ],
];

const res = [false, false, false, true, true, false];

cases.forEach((item: [string, string], index) =>
  console.log(res[index] === isMatch(item[0], item[1]))
);