递归改动态规划:正则匹配

题目描述
请实现一个函数用来匹配包括’.‘和’‘的正则表达式。模式中的字符’.‘表示任意一个字符,而’'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但是与"aa.a"和"ab*a"均不匹配

递归解法,​原因都在注释里: ​

public class Solution {
   
   public boolean match(char[] str, char[] pattern) {
   
        return  process(str, pattern, 0, 0);
    }
 
    // 看 str[si...ends] 的字符, 能不能被 pattern[pi...ends] 所匹配
    private boolean process(char[] str, char[] pattern, int si, int pi) {
   
        // 如果 pattern 的字符走完了
        if (pi == pattern.length ) {
   
            // 看 str 字符有没有走完。 没走完就直接返回 false, 走完就是全部匹配完了。。。
            // 注意这里是 可以直接返回结果的~
            return si == str.length;
        }
        
        
        // 如果 pi 来到了最后一个字符; 或者 pi 的下一个字符 不是 *
        if (pi + 1 == pattern.length || pattern[pi + 1] != '*') {
   
            // 看 str 的情况: 
            // str要有字符可以匹配; 
            // pattern 上是 . 或者 pattern和str的字符可以匹配;
            // 都接下去一位,接着看能不能匹配。
            return si != str.length && (str[si] == pattern[pi] || pattern[pi] == '.') 
                && process(str, pattern, si+1, pi+1);
        }
        
        
        // pi 的下一个字符是 * 的情况: 
        // str 要有字符可以匹配,
        // pattern 上是 . 或者 pattern和str的字符可以匹配;
        // * 可以匹配0位或任意位:所以这个while循环就是匹配 0 ... str.length 位的情况,有true直接 返回即可
        while (si != str.length && (str[si] == pattern[pi] || pattern[pi] == '.')) {
   
            if ( process(str, pattern, si, pi+2) ) {
   
                return true;
            }
            si++;
        }
        
        // str 字符走完了, 看 pattern 之后的能不能匹配
        return process(str, pattern, si, pi+2);
    }
}

动态规划解法 :

class Solution {
   
    public boolean isMatch(char[] str, char[] pattern) {
   
        if (str == null && pattern == null) {
   
            return true;
        }
        if (str == null || pattern == null) {
   
            return false;
        }
        int slen = str.length;
        int plen = pattern.length;
        
        // 初始化 dp 矩阵
        boolean[][] dp = initDP(str, pattern);

        // 填充 dp 矩阵
        for (int i =  slen - 1; i >= 0; i--) {
   
            for (int j = plen - 2; j >= 0; j--) {
   
                // pattern 下一位的字符不为 '*' 的情况
                if (pattern[j+1] != '*') {
   
                    // 看当前字符是否匹配, 都走一位后是否匹配
                    dp[i][j] = (str[i] == pattern[j] || pattern[j] == '.') 
                        && dp[i+1][j+1];
                } else {
   
                    // pattern 下一位的字符为 '*' 的情况
                    // * 可以匹配0位或任意位, 依次看匹配 0位、1位 ... 到末尾位的情况
                    int si = i;
                    while (si != slen && (str[si] == pattern[j] || pattern[j] == '.')) {
   
                        if (dp[si][j+2]) {
   
                            dp[i][j] = true;
                            break;
                        }
                        si++;
                    }
                    // str 走完单独算一下, 上面的 str[si] 中会越界
                    if (dp[i][j] == false) {
   
                        dp[i][j] = dp[si][j+2];
                    }
                }
            }
        }

        // 想要的结果
        return dp[0][0];
    }


    // 该 dp 矩阵中, (i, j) 依赖 (i+1, j+1) 和 (i, j+2),(i+1, j+2)...(str.length, j+2) 的位置
    // 所以, 要先把最后 2 列, 最后 1 行, 填充完整。 这样就可以推导出任何一点位置上的值了
    private boolean[][] initDP(char[] str, char[] pattern){
   
        int slen = str.length;
        int plen = pattern.length;
        boolean[][] dp = new boolean[slen+1][plen+1];
        
        // 倒数第一列, 都走完肯定为 true
        dp[slen][plen] = true;  

        // 倒数第二列, 看 pattern 和 str 的最后一个字符相不相等,或者 pattern 上是否为 '.' ; 注意边界问题
        if (slen > 0 && plen > 0 && ( str[slen-1] == pattern[plen-1] || pattern[plen-1] == '.' )) {
   
            dp[slen-1][plen-1] = true;
        }

        // 倒数第一行: str 走完了, 就看 pattern 是否可以匹配。
        for (int j = plen - 2; j >= 0; j = j - 2) {
   
            // pattern 上的字符不是 '*', 并且下一位是 '*' , 才能够匹配得上 ; 
            if (pattern[j] != '*' && pattern[j+1] == '*') {
   
                dp[slen][j] = true;
            } else {
   
                // 只要有 1 处开始匹配不上, 前面的就都不行, 因为pattern后面还有字符无处匹配了。
                break;  
            }
        }

        return dp;
    }
}

全部评论

相关推荐

Java抽象带篮子:难蚌,点进图片上面就是我的大头😆
点赞 评论 收藏
分享
11-27 12:43
已编辑
门头沟学院 C++
点赞 评论 收藏
分享
评论
点赞
收藏
分享
正在热议
# 25届秋招总结 #
442405次浏览 4511人参与
# 春招别灰心,我们一人来一句鼓励 #
41942次浏览 531人参与
# 阿里云管培生offer #
120224次浏览 2219人参与
# 地方国企笔面经互助 #
7961次浏览 18人参与
# 同bg的你秋招战况如何? #
76670次浏览 561人参与
# 虾皮求职进展汇总 #
115499次浏览 886人参与
# 北方华创开奖 #
107430次浏览 599人参与
# 实习,投递多份简历没人回复怎么办 #
2454658次浏览 34857人参与
# 实习必须要去大厂吗? #
55771次浏览 961人参与
# 提前批简历挂麻了怎么办 #
149901次浏览 1977人参与
# 投递实习岗位前的准备 #
1195935次浏览 18548人参与
# 你投递的公司有几家约面了? #
33205次浏览 188人参与
# 双非本科求职如何逆袭 #
662208次浏览 7394人参与
# 如果公司给你放一天假,你会怎么度过? #
4753次浏览 55人参与
# 机械人春招想让哪家公司来捞你? #
157628次浏览 2267人参与
# 如果你有一天可以担任公司的CEO,你会做哪三件事? #
11561次浏览 287人参与
# 发工资后,你做的第一件事是什么 #
12704次浏览 62人参与
# 工作中,努力重要还是选择重要? #
35804次浏览 384人参与
# 参加完秋招的机械人,还参加春招吗? #
20126次浏览 240人参与
# 我的上岸简历长这样 #
452016次浏览 8088人参与
# 实习想申请秋招offer,能不能argue薪资 #
39299次浏览 314人参与
# 非技术岗是怎么找实习的 #
155866次浏览 2120人参与
牛客网
牛客企业服务