跳至主要內容

10. Regular Expression Matching


10. Regular Expression Matchingopen in new window

🔴   🔖  递归 字符串 动态规划  🔗 LeetCodeopen in new window

题目

Given an input string s and a pattern p, implement regular expression matching with support for '.' and '*' where:

  • '.' Matches any single character.​​​​
  • '*' Matches zero or more of the preceding element.

The matching should cover the entire input string (not partial).

Example 1:

Input: s = "aa", p = "a"

Output: false

Explanation: "a" does not match the entire string "aa".

Example 2:

Input: s = "aa", p = "a*"

Output: true

Explanation: '*' means zero or more of the preceding element, 'a'. Therefore, by repeating 'a' once, it becomes "aa".

Example 3:

Input: s = "ab", p = ".*"

Output: true

Explanation: ".*" means "zero or more (*) of any character (.)".

Constraints:

  • 1 <= s.length <= 20
  • 1 <= p.length <= 20
  • s contains only lowercase English letters.
  • p contains only lowercase English letters, '.', and '*'.
  • It is guaranteed for each appearance of the character '*', there will be a previous valid character to match.

题目大意

给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.''*' 的正则表达式匹配。

  • '.' 匹配任意单个字符
  • '*' 匹配零个或多个前面的那一个元素

所谓匹配,是要涵盖 整个 字符串 s 的,而不是部分字符串。

解题思路

使用动态规划来解决正则表达式匹配问题,可以使用一个二维数组 dp,其中 dp[i][j] 表示字符串 s 的前 i 个字符和模式 p 的前 j 个字符是否匹配。

动态规划的递推公式如下:

  1. 如果 p[j] 不是 '*',且当前字符 s[i]p[j] 匹配,则 dp[i][j] = dp[i-1][j-1],表示当前字符是否匹配取决于前面的字符是否匹配。
  2. 如果 p[j]'*',则有两种情况:
    • '*' 匹配零个字符,即 dp[i][j] = dp[i][j-2]
    • '*' 匹配多个字符,即 dp[i][j] = dp[i-1][j],前提是当前字符 s[i]p[j-1] 匹配。
  3. 初始条件为 dp[0][0] = true,表示空字符串和空模式匹配。
  4. 初始化动态规划表 dp 的第一行,即 dp[0][j],表示空字符串与模式 p 的前 j 个字符的匹配情况,要注意考虑第 j 个字符是 '*' 的情况,。

代码

/**
 * @param {string} s
 * @param {string} p
 * @return {boolean}
 */
var isMatch = function (s, p) {
  const match = (i, j) => {
    return s[i - 1] == p[j - 1] || p[j - 1] == ".";
  };

  const m = s.length;
  const n = p.length;
  const dp = new Array(m + 1).fill(0).map(() => new Array(n + 1).fill(false));

  // 空字符串和空模式匹配
  dp[0][0] = true;

  // 初始化 dp[0][j],处理 p 中可能出现 '*' 的情况
  for (let j = 1; j <= n; j++) {
    if (p[j - 1] == "*") {
      dp[0][j] = dp[0][j - 2];
    }
  }

  for (let i = 1; i <= m; i++) {
    for (let j = 1; j <= n; j++) {
      if (match(i, j)) {
        dp[i][j] = dp[i - 1][j - 1];
      } else if (p[j - 1] == "*") {
        dp[i][j] = dp[i][j - 2] || (dp[i - 1][j] && match(i, j - 1));
      }
    }
  }
  return dp[m][n];
};

相关题目

相关题目
- [44. 通配符匹配](https://leetcode.com/problems/wildcard-matching)