【剑指offer】面试题19:正则表达式匹配

完整代码地址

完整代码地址

题目

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

思路

正则表达式中有三种情况:
a.普通字符
b.字符’.’
c.普通字符或’.’ + 字符’*’

碰到情况a、b都直接对比可以匹配,
难点在于处理情况c
情况c可以分两种子情况处理:
c1.字符串的首字母与模式的首字母不匹配,模式直接右移两格(相当于’*’前面的字符出现了0次)
c2.字符串的首字母与模式的首字母匹配,则:
  字符串右移一格,模式不移动(’*’前面的字符出现了不止一次)
  或字符串右移一格,模式右移两格(’*’前面的字符出现了刚好一次)
  或字符串不移动,模式右移两格(’*’前面的字符出现了0次)

当字符串和模式同时走到结尾+1的位置,则表示匹配
当字符串走到结尾+1的位置,模式还没走到结尾+1的位置,还要继续匹配(因为模式后面可能还有a*b*可以匹配0个字符串)
当字符串还没走到结尾+1的位置,模式走到结尾+1的位置,则表示不匹配

代码

public class _19_RegularExpressionsMatching {

    public boolean match(char[] str, char[] pattern) {
        if(str == null || pattern == null)
            return false;

        return match(str, 0, pattern, 0);
    }

    private boolean match(char[] str, int strIndex, char[] pattern, int patternIndex) {
        if(strIndex == str.length && patternIndex == pattern.length)
            return true;
        if(patternIndex == pattern.length)
            return false;

        int patternNextIndex = patternIndex + 1;

        // 模式下一个字符为'*'
        if(patternNextIndex < pattern.length && pattern[patternNextIndex] == '*') {
            // str已经走到结尾 || str的字母不等于pattern的字母
            if(strIndex == str.length || 
                    (str[strIndex] != pattern[patternIndex] && pattern[patternIndex] != '.')) {
                return match(str, strIndex, pattern, patternIndex + 2);
            }
            else {
                return match(str, strIndex + 1, pattern, patternIndex + 2) ||
                        match(str, strIndex, pattern, patternIndex + 2) ||
                        match(str, strIndex +1, pattern, patternIndex);
            }
        }
        // 模式下一个字符不为'*' && str走到了结尾 
        else if(strIndex == str.length)
            return false;
        else if(str[strIndex] == pattern[patternIndex] || pattern[patternIndex] == '.')
            return match(str, strIndex + 1, pattern, patternIndex + 1);

        return false;
    }

}

测试

public static void main(String[] args) {
    test1();
    test2();
    test3();
    test4();
}

/**
 * 功能测试
 * 0. 没有'.'和'*'
 * 1. '.'
 * 2. '.' + '*'
 * 3. '*'匹配0次
 * 4. '*'匹配多次
 * 5. '*'匹配一次
 */
private static void test1() {
    _19_RegularExpressionsMatching rem = new _19_RegularExpressionsMatching();
    boolean b = rem.match(new char[] {'a','a','b','c'}, new char[] {'a','a','b','c'});
    MyTest.equal(b, true);

    b = rem.match(new char[] {'a','a','a','b'}, new char[] {'a','.','.','.'});
    MyTest.equal(b, true);

    b = rem.match(new char[] {'a','a','a','b'}, new char[] {'a','.','*'});
    MyTest.equal(b, true);

    b = rem.match(new char[] {'a','b'}, new char[] {'a','a','*','b'});
    MyTest.equal(b, true);

    b = rem.match(new char[] {'a','b'}, new char[] {'a','b', '*'});
    MyTest.equal(b, true);

    b = rem.match(new char[] {'a','a','a','b'}, new char[] {'a','*','b'});
    MyTest.equal(b, true);
    System.out.println("====================================================");
}

/**
 * 功能测试
 * 0. 没有'.'和'*'
 * 1. '.'
 * 2. '.' + '*'
 * 3. '*'匹配0次
 * 4. '*'匹配多次
 * 5. '*'匹配一次
 */
private static void test2() {
    _19_RegularExpressionsMatching rem = new _19_RegularExpressionsMatching();
    boolean b = rem.match(new char[] {'a','a','b','c'}, new char[] {'a','a','b'});
    MyTest.equal(b, false);

    b = rem.match(new char[] {'a','a','a','b'}, new char[] {'a','.','.'});
    MyTest.equal(b, false);

    b = rem.match(new char[] {'a','a','a','b'}, new char[] {'a','.','*','c'});
    MyTest.equal(b, false);

    b = rem.match(new char[] {'a','b'}, new char[] {'a','a','*'});
    MyTest.equal(b, false);

    b = rem.match(new char[] {'a','b'}, new char[] {'a','b', '*','c'});
    MyTest.equal(b, false);

    b = rem.match(new char[] {'a','a','a','b'}, new char[] {'a','*'});
    MyTest.equal(b, false);
    System.out.println("====================================================");
}

/**
 * 边界测试
 * 1. '1' - '1'
 * 2. '1' - '.'
 * 3. '1' - '1','*'
 * 4. '1' - '.','*'
 */
private static void test3() {
    _19_RegularExpressionsMatching rem = new _19_RegularExpressionsMatching();
    boolean b = rem.match(new char[] {'1'}, new char[] {'1'});
    MyTest.equal(b, true);

    b = rem.match(new char[] {'1'}, new char[] {'.'});
    MyTest.equal(b, true);

    b = rem.match(new char[] {'1'}, new char[] {'1','*'});
    MyTest.equal(b, true);

    b = rem.match(new char[] {'1'}, new char[] {'.','*'});
    MyTest.equal(b, true);
    System.out.println("====================================================");
}

/**
 * 极端测试
 */
private static void test4() {
    _19_RegularExpressionsMatching rem = new _19_RegularExpressionsMatching();
    boolean b = rem.match(null, new char[] {'1'});
    MyTest.equal(b, false);

    b = rem.match(new char[] {'1'}, null);
    MyTest.equal(b, false);

    b = rem.match(null, null);
    MyTest.equal(b, false);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值