剑指offer 19 正则表达式匹配

思路:动态规划

当前的匹配结果由前面的匹配结果得出,所以需要建立一个二维数组来保存各个状态的结果。

根据两个字符串长度创建二维数组。(这里注意,需要将空字符状态也记录下来)

以用例 abcde 和 a.*f*d*e举例创建如下数组dp[][],T表示true  F表示False

nullabcde
nullTFFFFF
aFTFfff
.FF
*FT
fF
*F
dF
*F
eF

已知条件: 匹配字符串s中的字符只包含字母,正则表达式字符串P包含字母,"."和"*".

所以分三种情况

情况1:字母和字母匹配

        匹配结果:

                1.1相等:dp[i][k] = dp[i-1][k-1]

                1.2不相等:dp[i][k] = false

情况2:字母和'.'匹配

         dp[i][k] = dp[i-1][k-1]

情况3:字母和'*'匹配 (重点在于情况三的处理)

        如果遇到‘*’,那么'*'前面的字母(非‘.’字符,‘.’情况下面讨论)可以出现N次(N>=0)

        如果N == 0,前面的字符一次也不出现

                                即 dp[i][k] = dp[i-2][k];

        如果N >= 1 , 前面的字符肯定出现,那么s的末尾字母必须等于'*'前面的字母,否则肯定是false

                                即  p[i-1] != s[k]     =>    dp[i][k] = false

如果相等的话(p[i-1] == s[k])  比如 "####C" 和 "###C*"举例,当前的匹配结果等于"####"和"###C*"的匹配结果或者"####C"和"###C"的匹配结果,

                                即              dp[i][k] = dp[i][k-1] || dp[i-1][k]

所以我们对情况三做下归纳:

        dp[i][k] = dp[i-2][k] || (p[i-1] == s[k] && dp[i][k-1])

最后将思路转化成代码。

public boolean isMatch(String s, String p) {
        boolean dp[][] = new boolean[p.length() + 1][s.length() + 1];
        for (int i = 0; i <= p.length(); i++) {
            for (int k = 0; k <= s.length(); k++) {
                if(i == 0  && k == 0) {
                    dp[i][k] = true;
                } else if (i == 0) {
                    dp[i][k] = false;
                } else if (k == 0) {
                    if(i >= 2 && p.charAt(i-1) == '*') {
                        dp[i][k] = dp[i-2][k];
                    } else {
                        dp[i][k] = false;
                    }
                } else {
                    isTrue(dp, s, p, k, i);
                }
            }
        }
        return dp[p.length()][s.length()];
    }

    public void isTrue(boolean dp[][], String s, String p, int s_index, int p_index) {
        int s_str_index = s_index - 1;
        int p_str_index = p_index - 1;

        if (p.charAt(p_str_index) != '.' && p.charAt(p_str_index) != '*') {
            //情况1
            if (s.charAt(s_str_index) == p.charAt(p_str_index)) {
                dp[p_index][s_index] = dp[p_index - 1][s_index - 1];
            } else {
                dp[p_index][s_index] = false;
            }
        } else if (p.charAt(p_str_index) == '.') {
            //情况2
            dp[p_index][s_index] = dp[p_index - 1][s_index - 1];
        } else {
            //情况3
            char preChar = p.charAt(p_str_index - 1);
            boolean isMatch = preChar == '.' || preChar == s.charAt(s_str_index);
            dp[p_index][s_index] = (p_index - 2 >= 0 && dp[p_index - 2][s_index]) || (isMatch && dp[p_index][s_index - 1]) || dp[p_index - 1][s_index];
        }
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值