LeetCode破解之正则表达式

206 阅读2分钟

「这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战

题目描述

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

'.' 匹配任意单个字符 '*' 匹配零个或多个前面的那一个元素 所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。

示例 1:

输入:s = "aa" p = "a" 输出:false 解释:"a" 无法匹配 "aa" 整个字符串。

示例 2:

输入:s = "aa" p = "a*" 输出:true 解释:因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。

解题思路

递归

分析:因为模板pattern有两个不同状态‘’和‘.’,所以我们以模板字符串来考虑递归条件,主要有以下三种情况:

  1. 模板串>=2且第二个为,组成为: ch,* 和 .,*
  2. 模板>=2 ch,ch 和 .,ch 和 ch,. 和 .,.
  3. 模板=1 (等于0时候在函数入口就处理了) ch 和 .
class Solution {
  public boolean isMatch(String s, String p) {
        if (s == null || p == null) {
            return false;
        }
        //需要分别取出s和p为空的情况,所以memo数组大小+1
        Boolean[][] memo = new Boolean[s.length() + 1][p.length() + 1];
        return isMatch(s, 0, p, 0, memo);
    }

    private boolean isMatch(String s, int sIndex, String p, int pIndex, Boolean[][] memo) {
        if (sIndex == s.length() && pIndex == p.length()) {
            return true;
        }
        if (pIndex == p.length() && sIndex < s.length()) {
            return false;
        }
        if (memo[sIndex][pIndex] != null) {
            return memo[sIndex][pIndex];
        }
        boolean ret = false;
        if (pIndex + 1 < p.length() && p.charAt(pIndex + 1) == '*') {
            if (sIndex < s.length() && ((s.charAt(sIndex) == p.charAt(pIndex) || p.charAt(pIndex) == '.'))) {
                ret = isMatch(s, sIndex + 1, p, pIndex, memo) || isMatch(s, sIndex, p, pIndex + 2, memo);
            } else {
                ret = isMatch(s, sIndex, p, pIndex + 2, memo);
            }
        } else {
            if (pIndex < p.length() && sIndex < s.length() && (s.charAt(sIndex) == p.charAt(pIndex) || p.charAt(pIndex) == '.')) {
                ret = isMatch(s, sIndex + 1, p, pIndex + 1, memo);
            } else {
                ret = false;
            }
        }
        memo[sIndex][pIndex] = ret;
        return ret;
    }
}

动态规划

dp[i][j] 表示s的前i个字符和p的前j个字符是否匹配。那么,主要分两种情况。

  • 匹配0个,也就是 dp[i][j] == dp[i][j-2]
  • 匹配多个,dp[i][j] = dp[i-1][j]表示即可。
public boolean isMatch(String s, String p) {
        if (s == null || p == null || (!p.isEmpty() && p.charAt(0) == '*')) {
            return false;
        }
        int m = s.length();
        int n = p.length();
        boolean[][] dp = new boolean[m + 1][n + 1];
        dp[0][0] = true;
        for (int i = 0; i < n; i++) {
            //"a*b*c*d"
            if (p.charAt(i) == '*' && dp[0][i - 1]) {
                dp[0][i + 1] = true;
            }
        }
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                //s: abcd
                //p: abc.
                if (p.charAt(j) == s.charAt(i) || p.charAt(j) == '.') {
                    dp[i + 1][j + 1] = dp[i][j];
                } else if (p.charAt(j) == '*'){
                    //递归公式
                    //s: abcd
                    //p: abcdd*
                    if (p.charAt(j - 1) == s.charAt(i) || p.charAt(j - 1) == '.') {
                        dp[i + 1][j + 1] = dp[i][j + 1];
                    }
                    //s: abcd
                    //p: abcde*
                    dp[i + 1][j + 1] |= dp[i + 1][j - 1];
                }
            }
        }
        return dp[m][n];
    }