FPG-Alan / leetcode

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

10. 正则表达式匹配

FPG-Alan opened this issue · comments

https://leetcode.cn/problems/regular-expression-matching/

动态规划

dp[i][j] 表示 p[0~j)字串能否匹配s[0~i)字串, 最终结果就是dp[s.length][p.length] (注意, 这里采取左闭右开区间, 为了防止在j-2时数组越界)

状态转移公式需要根据p[j-1]的值分情况来看:

  1. p[j-1]是字母或'.', 则dp[i][j] => dp[i-1][j-1] && (s[i-1] === p[j-1] || p[j-1] === '.')
  2. p[j-1]是'*':
    • 若p[j-2] === s[i-1]:
      • 让'*'匹配零次,此时dp[i][j] => dp[i][j-2]
      • 让'*'匹配一次或多次,此时dp[i][j] => dp[i-1][j]
    • p[j-2] !== s[i-1], 此时只能让'*'匹配零次 dp[i][j] => dp[i][j-2]
var isMatch = function (s, p) {
    const dp = new Array(s.length + 1);
    for (let i = 0, l = dp.length; i < l; i += 1) {
      dp[i] = new Array(p.length + 1).fill(false);
    }

    dp[0][0] = true;
    for (let j = 1; j < p.length + 1; j++) {
      if (p[j - 1] == "*") dp[0][j] = dp[0][j - 2];
    }

    for (let i = 1, l = dp.length; i < l; i += 1) {
      for (let j = 1, k = dp[i].length; j < k; j += 1) {
        if (p[j - 1] === "." || p[j - 1] === s[i - 1]) {
          dp[i][j] = dp[i - 1][j - 1];
        } else if (p[j - 1] === "*") {
          if (p[j - 2] === s[i - 1] || p[j - 2] === ".") {
            // 此时可以选择*匹配模式
            // 若匹配0次, 直接扔掉, 那么i不变, j往前两位(扔掉*和前面匹配的那个字母)
            // 若匹配1次, 则i往前一位, j不变, 在下一轮继续匹配
            // 若匹配多次, 和匹配一次同理
            dp[i][j] = dp[i][j - 2] || dp[i - 1][j];
          } else if (p[j - 2] !== s[i - 1]) {
            // *前一位不匹配, 此时若还想继续匹配, 只能将*视为匹配0次
            dp[i][j] = dp[i][j - 2];
          }
        }
      }
    }
    return dp[s.length][p.length];
  };

  console.log(isMatch("aab", "c*a*b"));