[2021校招必看之Java版《剑指offer》-52] 正则表达式匹配

1、题目描述

  【JZ52】请实现一个函数用来匹配包括'.''*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。
  在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但是与"aa.a""ab*a"均不匹配。
  知识点:字符串,动态规划,递归
  难度:☆☆☆

2、解题思路

  字符串的匹配是把目标串和模式串的每一个字符挨个比较,每一次比较,都会针对三种情况进行讨论,三种情况分别是:普通字符、'*'字符、‘.’字符。

  1、当是普通字符时,一样则匹配,不一样则不匹配;

  2、当是‘.’字符时,直接匹配;

  3、当是'*'字符时,'*'字符表示前一个字符重复 0 次或者多次,又可以分成两种情况讨论:
  3.1 重复 0 次,那么目标串回去前一个字符,模式串走下一个字符,重新匹配;
  3.2 重复 1 次或多次,那么目标串不断往下遍历,比如目标串走了 3 步就开始和 '*'字符 前面的字符不匹配,就可以当成重复了 3 次。

  图解如下:
  情况1:普通字符,且匹配,目标串和模式串都往下走一步,继续判断;
在这里插入图片描述
  情况2:'.'字符,直接匹配,目标串和模式串都往下走一步,继续判断;
在这里插入图片描述
  情况3:当前元素匹配了,发现下一个模式串字符是'*'
  3.1 当做重复了 0 次,目标串不动,模式串走 2 步;
在这里插入图片描述
  3.2 当重复了 1 或多次,模式串不动,目标串不断往下走,每走一步就判断一次。
在这里插入图片描述
  1、递归函数功能:match(s, p) -> bool, 表示p是否可以匹配s

  2、递归终止条件:
  2.1 如果s 和 p 同时为空,表明正确匹配;
  2.2 如果s不为空,p为空,表明,不能正确匹配;
  2.3 如果s为空,p不为空,需要计算,不能直接给出结果;

3、解题代码

package pers.klb.jzoffer.hard;

/**
 * @program: JzOffer2021
 * @description: 正则表达式匹配
 * @author: Meumax
 * @create: 2020-07-22 09:42
 **/
public class MatchString {
    public boolean match(char[] str, char[] pattern) {
        //return matchTwo(str, 0, str.length, pattern, 0, pattern.length);
        return doMatch(str, pattern, 0, 0);
    }

    private boolean doMatch(char[] str, char[] pattern, int strIndex, int patternIndex) {
        // 目标串和模式串都为空串,匹配
        // str.length - strIndex 表示:包含当前字符在内,还有多少个字符没有匹配
        // pattern.length - patternIndex 表示:包含当前模式字符在内,还有多少个模式字符没用上
        if ((str.length - strIndex == 0) && (pattern.length - patternIndex == 0)) {
            return true;
        }

        // 目标串不为空,模式串为空,不匹配
        if ((str.length - strIndex != 0) && (pattern.length - patternIndex == 0)) {
            return false;
        }

        // 目标串遍历完了,模式串可以遍历完也可以没有遍历完
        if (str.length - strIndex == 0) {
            // 如果模式串还有剩余字符,遍历剩余字符,看是否满足条件
            while (pattern.length - patternIndex != 0) {
                // 不满足的情况1:只剩下一个字符,且这个字符还不为 ‘*’,比如:'a' 或者 '.'
                // 不满足的情况2:剩下不止一个字符,第 0 个字符不为 ‘*’ 也就算了,第 1 个字符还是不为 ‘*’。比如:'a' '.'
                if (pattern[patternIndex] != '*' && (pattern.length - patternIndex - 1 == 0 || pattern[patternIndex + 1] != '*')) {
                    return false;
                }
                // 遍历下一个字符
                patternIndex++;
            }
            // while结束还没 return ,说明剩余的字符都满足要求
            // 满足的情况:剩余的模式串字符肯定要用*来消除,比如说:a * b * c *,这种结构的无论多长,都可以因为 * 表示 0 个来消除。
            return true;
        }

        // 目标串先不管,模式串已经遍历到最后一个字符了
        if (pattern.length - patternIndex == 1) {
            if (str[strIndex] == pattern[patternIndex] || pattern[patternIndex] == '.')
                // 如果目标串当前字符和模式串当前字符能匹配,则继续往下匹配
                return doMatch(str, pattern, strIndex + 1, patternIndex + 1);
            else {
                // 当前字符不匹配
                return false;
            }
        }

        // 目标串和模式串都不为空
        if (pattern[patternIndex + 1] != '*') { // 模式串下一个字符不是 *
            // 判断当前字符是否匹配
            if ((str[strIndex] == pattern[patternIndex] || pattern[patternIndex] == '.')) {
                // 匹配,则继续匹配下一个字符
                return doMatch(str, pattern, strIndex + 1, patternIndex + 1);
            } else {
                // 不匹配则返回 false
                return false;
            }
        } else { // 模式串下一个字符是 *
            boolean flag = false;
            // 重复 1 次或多次
            if ((str[strIndex] == pattern[patternIndex] || pattern[patternIndex] == '.')) {
                flag = doMatch(str, pattern, strIndex + 1, patternIndex);
            }
            // 重复 0 次和重复 1 到多次的综合结果
            return flag || doMatch(str, pattern, strIndex, patternIndex + 2);
        }
    }
}

4、解题心得

  本题难度适中,就是对所有的情况不断的 if 和递归操作,比较繁琐。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值