LeetCode题解_19_正则表达式匹配

该博客详细介绍了如何使用动态规划解决LeetCode上的第19题——正则表达式匹配问题。解释了动态规划的状态定义,给出了匹配过程的思路,并提供了相关代码实现。同时,分析了算法的时间复杂度和空间复杂度,均为O(mn),其中m和n分别代表字符串和模式的长度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

19. 正则表达式匹配(动态规划)

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

动态规划

思路

定义状态dp[i][j] ,表示s的前 i 个字符与p的前 j 个字符是否匹配
在这里插入图片描述

以一个例子详解动态规划转移方程:
S = abbbbc
P = ab*d*c
1. 当 i, j 指向的字符均为字母(或 '.' 可以看成一个特殊的字母)时,
   只需判断对应位置的字符即可,
   若相等,只需判断 i,j 之前的字符串是否匹配即可,转化为子问题 f[i-1][j-1].
   若不等,则当前的 i,j 肯定不能匹配,为 false.
   
       f[i-1][j-1]   i
            |        |
   S [a  b  b  b  b][c] 
   
   P [a  b  *  d  *][c]
                     |
                     j
   

2. 如果当前 j 指向的字符为 '*',则不妨把类似 'a*', 'b*' 等的当成整体看待。
   看下面的例子

            i
            |
   S  a  b [b] b  b  c  
   
   P  a [b  *] d  *  c
            |
            j
   
   注意到当 'b*' 匹配完 'b' 之后,它仍然可以继续发挥作用。
   因此可以只把 i 前移一位,而不丢弃 'b*', 转化为子问题 f[i-1][j]:
   
         i
         | <--
   S  a [b] b  b  b  c  
   
   P  a [b  *] d  *  c
            |
            j
   
   另外,也可以选择让 'b*' 不再进行匹配,把 'b*' 丢弃。
   转化为子问题 f[i][j-2]:

            i
            |
   S  a  b [b] b  b  c  
    
   P [a] b  *  d  *  c
      |
      j <--

3. 冗余的状态转移不会影响答案,
   因为当 j 指向 'b*' 中的 'b' 时, 这个状态对于答案是没有用的,
   原因参见评论区 稳中求胜 的解释, 当 j 指向 '*' 时,
   dp[i][j]只与dp[i][j-2]有关, 跳过了 dp[i][j-1].

代码

class Solution {
    public boolean isMatch(String s, String p) {
        int m = s.length(), n = p.length();
        boolean dp[][] = new boolean[m+1][n+1];
        dp[0][0] = true;//空字符串也能匹配
        for(int i = 0;i <= m;i++){
            for(int j = 1;j <= n;j++){
                if(j >= 2 && p.charAt(j - 1) == '*'){
                    dp[i][j] = dp[i][j - 2];
                    if(isCharMatch(s,p,i,j-1)){
                        dp[i][j] = dp[i - 1][j] || dp[i][j];
                    }
                }else if(isCharMatch(s,p,i,j)) {
                    dp[i][j] = dp[i - 1][j - 1];
                }
            }
        }
        return dp[m][n];
    }

    public boolean isCharMatch(String s,String p,int i,int j){
        if(i == 0){
            return false;
        }
        if(p.charAt(j - 1) == '.'){
            return true;
        }
        return s.charAt(i - 1) == p.charAt(j - 1);
    }
}

复杂度

  1. 时间复杂度:O(mn)。其中m和n分别是字符串s和p的长度。
  2. 空间复杂度:O(mn)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值