正则表达式匹配

问题描述

给定一个字符串 (s) 和一个字符模式 §。实现支持 ‘.’ 和 ‘*’ 的正则表达式匹配。

‘.’ 匹配任意单个字符。
‘*’ 匹配零个或多个前面的元素。

匹配应该覆盖整个字符串 (s) ,而不是部分字符串。

说明:

  • s 可能为空,且只包含从 a-z 的小写字母。
  • p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。

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

示例 2:
输入:
s = “aa”
p = “a*”
输出: true
解释: ‘*’ 代表可匹配零个或多个前面的元素, 即可以匹配 ‘a’ 。因此, 重复 ‘a’ 一次, 字符串可变为 “aa”。

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

示例 4:
输入:
s = “aab”
p = “c*a*b”
输出: true
解释: ‘c’ 可以不被重复, ‘a’ 可以被重复一次。因此可以匹配字符串 “aab”。

示例 5:
输入:
s = “mississippi”
p = “mis*is*p*.”
输出: false

我的答案

思想

首先可以分为两种情况

  • p的下一个字符不为"*",直接匹配两个字符,若不想等或者p的当前字符不为零则直接返回false

  • p的下一个字符为"*",匹配两个字符若相等则s的指针后移一位,若不想等则p的指针后移一位(*可以匹配零个字符),若相等则s的指针后移一位继续匹配

代码
class Solution {
    public boolean isMatch(String s, String p) {
        if (p.isEmpty()){
            return s.isEmpty();
        }
        int i = 0;
        int j = 0;
        while(i != s.length() && j != p.length()){
            if(s.charAt(i) == (p.charAt(j))){
                i++;
                j++;
            }else{
                if(p.charAt(j) == '.'){
                    i++;
                    j++;
                }else if(p.charAt(j) == '*'&&j>0){
                    if(p.charAt(j-1) == s.charAt(i)||(p.charAt(j-1)=='.')){
                        i++;
                        if(i==s.length()){
                            j++;
                        }
                    }else{
                        j++;
                    }
                }else if(j<(p.length()-1)&&p.charAt(j+1)=='*'){
                    j++;
                }else{
                    return false;
                }
            }
        }
        if(j<(p.length())&&p.charAt(j)==s.charAt(i-1)){
                                j++;
                            }
        
        if(i<s.length()||j<p.length()){
            return false;
        }
        return true;
    }
}
问题

大部分的字符串都可以匹配,但是例如s=“aaa”,p="a*a"就不可以,因为j无法向后移动,如果s=“aaaaaa”,p=“a*aaa”,也无法得出正确的结论,因为无法判断
*应该匹配几个a。

递归

官方给出的第一个解法,类似于我自己的答案,也可以说是暴力法

思想
  1. 设置一个变量用于匹配第一个字符,若匹配成功则置true,若不成功则置false
  2. 如果p的length>=2以及p的下一个字符为"*",若上面的变量为false截取p从两位后开始,若上面变量为true,则截取s从一位后开始,返回递归
  3. 若p的下一个字符不为"*"以及变量为true,则截取s和p一位后开始递归
代码
class Solution {
    public boolean isMatch(String text, String pattern) {
        if (pattern.isEmpty()) return text.isEmpty();
        boolean first_match = (!text.isEmpty() &&
                               (pattern.charAt(0) == text.charAt(0) || pattern.charAt(0) == '.'));

        if (pattern.length() >= 2 && pattern.charAt(1) == '*'){
            return (isMatch(text, pattern.substring(2)) ||
                    (first_match && isMatch(text.substring(1), pattern)));
        } else {
            return first_match && isMatch(text.substring(1), pattern.substring(1));
        }
    }
}

动态规划

思想
  1. 初始化数组,dp[s.length()+1][p.length[]+1],用于存储子问题结果
  2. 两层循环,外面循环s,里面循环p
  3. 第一次判断,与上面的相同,看是否相等或者p为
    “.”,记录变量。
  4. 如果s的下一个为"*",且记录的变量为false,则记录d[i][j]为d[i][j+2],若为true记录为d[i+1][j]
  5. 如果不为"*",则直接记录d[i][j]为d[i+1][j+1],遍历完成返回dp[0][0]
代码
class Solution {
    public boolean isMatch(String text, String pattern) {
        boolean[][] dp = new boolean[text.length() + 1][pattern.length() + 1];
        dp[text.length()][pattern.length()] = true;

        for (int i = text.length(); i >= 0; i--){
            for (int j = pattern.length() - 1; j >= 0; j--){
                boolean first_match = (i < text.length() &&
                                       (pattern.charAt(j) == text.charAt(i) ||
                                        pattern.charAt(j) == '.'));
                if (j + 1 < pattern.length() && pattern.charAt(j+1) == '*'){
                    dp[i][j] = dp[i][j+2] || first_match && dp[i+1][j];
                } else {
                    dp[i][j] = first_match && dp[i+1][j+1];
                }
            }
        }
        return dp[0][0];
    }
}

总结

基本上所有的算法判断的思路都是一样的,不同的是处理的方式,递归方式一般是不推荐使用的,不停的调用函数很浪费时间,而这个问题属于比较典型的动态规划,判断完一个字符判断下一个,而时间也比递归 要少得多。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值