剑指offer(55):正则表达式匹配

题目描述

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

分析

思路来源于剑指offer书籍,理解的还不是很透彻。

每次从字符串里拿出一个字符和模式中的字符去匹配。如果模式中的字符ch是’.’,那么它可以匹配字符串中的任意字符。如果模式中的字符ch不是’.’,而字符串中的字符也是ch,则它们同样相互匹配,接着匹配后面的字符。

当模式中的第二个字符不是’*’时,比较简单。如果字符串中的第一个字符和模式中的第一个字符相匹配,那么字符串和模式上都向后移动一个字符,然后匹配剩余的字符串和模式。如果字符串中的第一个字符和模式中的第一个字符不匹配,则直接返回false。

当模式中的第二个字符是’*’,比较复杂,可能有多种匹配方法。一个选择是在模式上向后移动两个字符。这相当于’*’和它前面的字符被忽略掉了,因为’*’可以匹配字符串中的0个字符。如果模式中的第一个字符和字符串中的第一个字符相匹配时,则在字符串向后移动一个字符,而在模式上有两个选择:向后移动两个字符,或者保持模式不变。

匹配状态
模式ba*ab的非确定有限状态机。当匹配进入状态2并且字符串的字符是’a’时,有两个选择:进入状态3,或者回到状态2。

当匹配进入状态2并且字符串的字符是’a’时,有两个选择:进入状态3(在模式上向后移动两个字符),或者回到状态2(模式保持不变)。

牛客AC:

package com.problem;

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

    public boolean match(char[] str, char[] pattern) {
        return isMatch(str, 0, pattern, 0);
    }

    public boolean isMatch(char[] str, int strIndex, char[] pattern, int patternIndex) {
        if (strIndex == str.length && patternIndex == pattern.length)   // 同时结束
            return true;        
        if (patternIndex >= pattern.length)     // pattern 先结束
            return false;
        if (strIndex == str.length)     // str结束
            return false;

        // patternIndex 还没到达倒数第二位
        if (patternIndex < pattern.length - 1) {
            // 如果下一位是 *
            if (pattern[patternIndex + 1] == '*') {
                if ((strIndex < str.length) && 
                        (str[strIndex] == pattern[patternIndex] || pattern[patternIndex] == '.')) {
                            // 第一种,模式上移动两个字符,相当于忽略‘*’和它前面的字符
                    return isMatch(str, strIndex, pattern, patternIndex + 2) ||     
                            // 第二种,当前字符匹配成功,模式上移动两个字符
                            isMatch(str, strIndex + 1, pattern, patternIndex + 2) || 
                            // 第三种,当前字符匹配成功,模式上保持不变
                            isMatch(str, strIndex + 1, pattern, patternIndex);
                } else
                    // 忽略'*'和它前面的字符
                    return isMatch(str, strIndex, pattern, patternIndex + 2);
            }
        }

        // 下一位不是‘*’,则只要匹配'.',匹配成功后,同时移动一个字符
        if (str[strIndex] == pattern[patternIndex] || pattern[patternIndex] == '.')
            return isMatch(str, strIndex + 1, pattern, patternIndex + 1);

        return false;
    }
}

参考
1. 何海涛,剑指offer名企面试官精讲典型编程题(纪念版),电子工业出版社

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值