动态规划来一波,无非就是三步解决问题

155 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第12天,点击查看活动详情

题目描述

思路

  • 很明显这道题解题思路就是动态规划。因为想要判断d[i][j]那么势必需要考虑d[i-1][j-1]的情况。这和我们之前说动态规划的时候思路是一致的。我们需要确定初始状态然后在确定变化方程以及边界就可以了。

image.png

  • 字符串类题目常用方法是状态机、动态规划、双指针的方法,IF-ELSE 写法对于字符串类题目非常不友好。对于匹配类题目,通常我们用动态规划来解决。

image.png

patter[j] == '*' 遇到 * 就要把它和前面看作一个整体,根据规则,它们有以下三种能力:

匹配零次:忽略这个组合,S(i)S(i) 和 P(j - 2)P(j−2) 能匹配的话就 OK,即

if (dp[i][j - 2]) 
    dp[i][j] = true;

正常情况下 ii 行 jj 列的 dp 数组,需要处理上面的特殊情况和写一堆判断是否处于开头的代码,因此我们增加一个初始行和初始列,简化代码简化逻辑。

第 0 列:代表模式串与 SS 前面的 "" 进行匹配,此时 ab 匹配 "" 我们判定为 true 就 OK。

第 0 行:由于匹配需要看 dp[i - 1][j - 1],为了方便编码我们引入第 0 行,代表 SS 与 PP 前面的 "" 进行匹配,此时 dp[0][0] 代表 "" 与 "" 的匹配,为 true。

但是我们还需要考虑一下特殊情况,就是我们匹配字符串时并没有生效。这个时候我们又改怎么做呢。这就是对应我们动态规划套路中的确定初始状态。确定初始状态之后我们就可以进行推到了

AC


    public boolean isMatch(String s, String p) {
        if (s == null || p == null) return false;
        int m = s.length(), n = p.length();
        if (m == 0 && n == 0) return true;
        if (n == 0) return false;

        boolean[][] dp = new boolean[m + 1][n + 1];
        char[] string = s.toCharArray();
        char[] pattern = p.toCharArray();

        dp[0][0] = true;

       
        for (int i = 1; i < dp[0].length; i++) {
            if (pattern[i - 1] == '*')
                dp[0][i] = dp[0][i - 2];
        }

        for (int i = 1; i < dp.length; i++) {
            for (int j = 1; j < dp[0].length; j++) {

                if (string[i - 1] == pattern[j - 1] || pattern[j - 1] == '.') {
                    dp[i][j] = dp[i - 1][j - 1];
                } else if (pattern[j - 1] == '*') {
                    // 匹配零次
                    dp[i][j] |= dp[i][j - 2];
                    // 匹配一次
                    dp[i][j] |= dp[i][j - 1];
                    // 匹配多次
                    dp[i][j] |= dp[i - 1][j] && (string[i - 1] == pattern[j - 2] || pattern[j - 2] == '.');
                }
            }
        }

        return dp[string.length][pattern.length];
    }