「力扣」第 10 题:正则表达式(递归、动态规划)

方法一:递归

Java 代码:

public class Solution {

    /**
     * 思想:递归,减而治之
     * '.' 匹配任意单个字符
     * '*' 匹配零个或多个前面的那一个元素
     *
     * @param s 文本串,有时候也用 t 表示
     * @param p 模式串
     * @return
     */
    public boolean isMatch(String s, String p) {
        // 先写递归终止条件,
        if (p.isEmpty()) {
            return s.isEmpty();
        }

        char[] sCharArray = s.toCharArray();
        char[] pCharArray = p.toCharArray();

        // 满足 firstMatch 就表示可以同时砍掉模式串 p 和文本串 s 的第 1 个字符
        // ① 第 1 个字符正正好相等
        // ② 模式串的第 1 个字符正正好是 '.',因为可以匹配任意单个字符
        boolean firstMatch = !s.isEmpty() && (sCharArray[0] == pCharArray[0] || pCharArray[0] == '.');

        // 当模式串的下一个是 *
        // ① * 号的作用是 0 次:模式串与前面的都不匹配,例如:s = 'bb',p = 'a*bb',模式串直接砍掉 2 个(连同 * 一起砍掉),继续匹配
        // ② * 号的作用是 1 次或者更多次:在满足 firstMatch 的前提下,s 砍掉 1 个然后继续
        if (p.length() > 1 && pCharArray[1] == '*') {
            if (isMatch(s, p.substring(2))) {
                return true;
            }
            return firstMatch && isMatch(s.substring(1), p);
        }
        return firstMatch && isMatch(s.substring(1), p.substring(1));
    }
}

方法二:动态规划

Java 代码:

public class Solution {

    public boolean isMatch(String s, String p) {
        int sLen = s.length();
        int pLen = p.length();

        char[] sCharArray = s.toCharArray();
        char[] pCharArray = p.toCharArray();

        // 记录文本符串 s[0, i) 是否匹配模式字符串 p[0, j)
        boolean[][] dp = new boolean[sLen + 1][pLen + 1];

        // 初始化 begin
        dp[0][0] = true;
        for (int j = 1; j < pLen; j++) {
            // 如果当前 p 看到的是 * ,直接砍掉 2 个模式串
            dp[0][j + 1] = pCharArray[j] == '*' && dp[0][j - 1];
        }
        // 初始化 end

        for (int i = 0; i < sLen; i++) {
            for (int j = 0; j < pLen; j++) {

                if (pCharArray[j] == '*') {
                    // 下面开始分类讨论
                    // 把 '*' 当前面的字符使用 0 次,全程注意有 1 个偏移的量
                    if (dp[i + 1][j - 1]) {
                        dp[i + 1][j + 1] = true;
                    } else {
                        // 就这里巨难理解

                        // 砍去文本串的头一个
                        dp[i + 1][j + 1] = firstMatch(sCharArray, pCharArray, i, j - 1) && dp[i][j + 1];
                    }

                } else {
                    dp[i + 1][j + 1] = firstMatch(sCharArray, pCharArray, i, j) && dp[i][j];
                }
            }
        }
        return dp[sLen][pLen];
    }

    private boolean firstMatch(char[] sCharArray, char[] pCharArray, int i, int j) {
        return sCharArray[i] == pCharArray[j] || pCharArray[j] == '.';
    }
}

同样套路的问题还有:

1、编辑距离;

2、最长公共子串;

3、最长回文子串。


以下的写法是备份,可以不看。

  • 递归写法 1

Java 代码:

public class Solution {

    // 递归 + 分类讨论
    // 使用递归的思想,第 1 个匹配了,后面的递归处理就可以了

    public boolean isMatch(String s, String p) {
        if (p.isEmpty()) {
            return s.isEmpty();
        }
        boolean firstMatch = !s.isEmpty() && (s.charAt(0) == p.charAt(0) || p.charAt(0) == '.');
        if (p.length() > 1 && p.charAt(1) == '*') {
            // '*' 匹配 0 次
            if (isMatch(s, p.substring(2))) {
                return true;
            }
            // '*' 至少匹配 1 次
            return firstMatch && isMatch(s.substring(1), p);
        }
        return firstMatch && isMatch(s.substring(1), p.substring(1));
    }

}
  • 递归写法 2

Java 代码:

public class Solution {
    public boolean isMatch(String s, String p) {
        if (p.length() == 0){
            return s.length() == 0;
        }

        boolean firstMatch = s.length() >= 1 && (s.charAt(0) == p.charAt(0) || p.charAt(0) == '.');

        if (p.length() > 1 && p.charAt(1) == '*'){
            if (isMatch(s, p.substring(2))){
                return true;
            }
            return firstMatch && isMatch(s.substring(1), p);
        }
        return  firstMatch && isMatch(s.substring(1), p.substring(1));
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值