leetcode10 正则表达式匹配

正则表达式匹配

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

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


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

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

示例 3:
输入:s = "ab", p = ".*"
输出:true
解释:".*" 表示可匹配零个或多个('*')任意字符('.')。

提示:
1 <= s.length <= 20
1 <= p.length <= 30
s 只包含从 a-z 的小写字母。
p 只包含从 a-z 的小写字母,以及字符 . 和 *。
保证每次出现字符 * 时,前面都匹配到有效的字符

 

解题思路:

dp[i][j] 表示匹配串s的前i个字符 和 模式串p前j个字符是否匹配

dp[0][0]= true 表示 s空串和p空串 由于模式串空串可以匹配匹配串空串 设置值为true

要求dp[i][j] 是否匹配 需要区分2种情况 p[j-1] 是否为 * 字符 第j个字符的索引为j-1

1.如果 p[j-1] == '*'
这里也有2种情况
1.1 当前*和前一个字符的组合 什么也没有匹配到 这里就相当于直接把模式串的当前的组合匹配去掉
此时dp[i][j]=dp[i][j-2]
1.2 当前*和前一个字符的组合 匹配到值了 则说明匹配串当前*的前一个字符 和当前匹配串的i个字符需要匹配
match(s,p,i,j-1)
如果dp[i][j]想要匹配成功 这里有两种情况 p[j-2] 是a-z的字母的一个字符 p[j-2] 是 .
1.2.1 如果p[j-2] == '.'
则dp[i][j] = dp[i-1][j]
1.2.2 如果p[j-2] 是a-z的一个字符
则 dp[i][j] = dp[i-1][j-1]
2. p[j-1] != '*'
计算dp[i][j]是否匹配的话 需要知道当前匹配串的第i个字符和模式串的第j个字符是否相等 或者 模式串的第j个 字符为. 就是字符匹配操作 match(s,p,i,j)
dp[i][j]=dp[i-1][j-1]

两种情况都使用到了匹配函数 下面列出匹配函数
// 注意在java种获取一个字符使用 s.charAt(i) 下面为了方便写成中括号
public boolen match(String s,String p,int i, int j){
if (i < 1 || j < 1) return false;
if (p[j - 1] == '.') return true;
return s[i - 1] == p[j - 1];
}

 

public static boolean isMatch(String s, String p) {
        int m = s.length();
        int n = p.length();
        //dp数组 dp[i][j]  表示s前i个字符和p前j个字符匹配的结果
        boolean[][] dp = new boolean[m + 1][n + 1];
        //dp[0][0] s空串和p空串匹配成功
        dp[0][0] = true;
        // dp[0][1] - dp[0][j] 要设置为false boolean数组默认初始值为false 因此不需要设置
        for (int i = 0; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                if (p.charAt(j - 1) == '*') {
                    // *表示 匹配零个或多个前面的那一个元素
                    // 如果匹配到字符* 则说明 *和前面字符的组合 可能匹配到 也可能什么也没匹配到
                    // 例如 s="" p="c*",s="c" p="c*",s="ccc" p="c*"  前面几种情况都是匹配的
                    // 所以这里处理第1种情况 直接丢弃这个组合的两个字符
                    // 根据已知条件可以知道*不可能是模式串p的第一个字符 下面的公式数组下标不可能越界
                    dp[i][j] = dp[i][j - 2];
                    // 这里处理第2种情况 让p串往前移动1个字符 和 s串的第i个字符匹配
                    if (match(s, p, i, j - 1)) {
                        // 匹配成功 则s前i个字符和p前j个字符匹配的结果
                        // 为 s前i-1个字符和p前j-1个字符匹配的结果
                        // 或者 * 的前面是.  则 s前i-1个字符和p的前i个字符匹配
                        dp[i][j] |= dp[i - 1][j - 1];
                        dp[i][j] |= dp[i - 1][j];
                    }
                } else {
                    if (match(s, p, i, j)) {
                        dp[i][j] = dp[i - 1][j - 1];
                    }
                }
            }
        }
        return dp[m][n];
    }

    public static boolean match(String s, String p, int i, int j) {
        if (j < 1 || i < 1) return false;
        // 模式串p 为. 则一定匹配
        if (p.charAt(j - 1) == '.') {
            return true;
        }
        return s.charAt(i - 1) == p.charAt(j - 1);
    }

 

posted @ 2022-06-21 14:31  荣超  阅读(27)  评论(0编辑  收藏  举报