【剑指offer】正则表达式匹配

🔥题目

请实现一个函数用来匹配包含’.‘和’*‘的正则表达式。
字符’.‘表示任意一个字符,’*'表示它前面的字符可以出现任意次(含0次)。

 

☘️解析

首先不难想到动态规划的含义:dp[i][j]表示原串的前i个字符与匹配串的前j个字符是否匹配(注意i,j都可取0)

明确了dp的含义,下面开始初始化:

1)原串和匹配串都为空串的情况。空串当然可匹配空串,因此有 dp[0][0] = true

2)原串为空串,匹配串不为空串的情况。这时竟然也可能匹配!这是因为’*‘的一个作用就是将前一个字符视为不存在。比如"a*b*c*"即可匹配空串。这种“将前一个字符视为不存在”的作用可以表示为,当扫描到’*'时,dp[0][j] = dp[0][j - 2]

3)原串不为空串,匹配串为空串的情况。很显然,一定无法匹配。因此有 dp[i][0] = false

完成了初始化,下面开始动态转移:

a)对’.'的处理。这非常简单,因为它可以表示任意一个字符,扫描到’.'可直接认为该位置的两个字符匹配成功。

b)对’*'的处理。这比较困难,这里用一个例子来说明。假设原串为"abcccc",匹配串为"abc*"。上面已经说明了’*'的一个作用,即“将前一个字符c视为不存在(作用1)”,这里还要用到它的另一个作用,即“将前一个字符c重复多次,因此可以将原串中与c相同的字符视为不存在(作用2)”。回到例子,首先使用作用2将原串转化为"abccc"、"abcc"、"abc"、"ab",然后使用作用1将匹配串转化为"ab",匹配成功!

 

🧊代码
class Solution {
    public boolean isMatch(String s, String p) {
       int m = s.length();
       int n = p.length();
       boolean[][] dp = new boolean[m + 1][n + 1];
       // 初始化(原串和匹配串都为空串的情况)
       dp[0][0] = true;
       // 初始化(原串为空串,匹配串不为空串的情况)
       for (int j = 2; j <= n; j++) {
           if (p.charAt(j - 1) == '*') {
               dp[0][j] = dp[0][j - 2];
           }
       }
       // 状态转移
       for (int i = 1; i <= m; i++) {
           for (int j = 1; j <= n; j++) {
               char ss = s.charAt(i - 1);
               char pp = p.charAt(j - 1);
               if (ss == pp || pp == '.') {
                   dp[i][j] = dp[i - 1][j - 1];
               } else if (pp == '*') {
                   dp[i][j] = ((p.charAt(j - 2) == ss || p.charAt(j - 2) == '.') && dp[i - 1][j]) || dp[i][j - 2];
               }
           }
       }
       return dp[m][n];
    }
}

 

🌸补充

这里再补充一个类似的题目,所使用通配符的含义有所不同。

请实现一个函数用来匹配包含’?‘和’*‘的正则表达式。
字符’?‘表示任何单个字符,’*'表示任意字符串(包括空字符串)。

class Solution {
    public boolean isMatch(String s, String p) {
        int m = s.length();
        int n = p.length();
        boolean[][] dp = new boolean[m + 1][n + 1];
        // s和p都为空串
        dp[0][0] = true;
        // s为空串,p不为空串
        for (int j = 1; j <= n; j++) {
            if (p.charAt(j - 1) == '*') {
                dp[0][j] = dp[0][j - 1];
            }
        }
        // 状态转移
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                char ss = s.charAt(i - 1);
                char pp = p.charAt(j - 1);
                if (ss == pp || pp == '?') {
                    dp[i][j] = dp[i - 1][j - 1];
                } else if (pp == '*') {
                    dp[i][j] = dp[i - 1][j] || dp[i][j - 1];
                }
            }
        }
        return dp[m][n];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值