剑指offer52 正则表达式匹配


剑指offer52

正则表达式匹配

题目描述

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

输入

“aaa”,”a*a”

输出

true

解法一:递归

首先,考虑特殊情况:

  1. 两个字符串都为空,返回true
  2. 当第一个字符串不空,而第二个字符串空了,返回false(因为这样,就无法
    匹配成功了,而如果第一个字符串空了,第二个字符串非空,还是可能匹配成
    功的,比如第二个字符串是“a*a*a*a*”,由于‘*’之前的元素可以出现0次,
    所以有可能匹配成功)

之后就开始匹配第一个字符,这里有两种可能:匹配成功或匹配失败。但考虑到pattern下一个字符可能是‘*’,这里我们分两种情况讨论:pattern下一个字符为‘*’或不为‘*’:

  • pattern下一个字符不为‘*’:这种情况比较简单,直接匹配当前字符。如果
    匹配成功,继续匹配下一个;如果匹配失败,直接返回false。注意这里的“匹配成功”,除了两个字符相同的情况外,还有一种情况,就是pattern的当前字符为‘.’,同时str的当前字符不为‘\0’。
  • pattern下一个字符为‘*’时,稍微复杂一些,因为‘*’可以代表0个或多个。这里把这些情况都考虑到:
    • a>当‘*’匹配0个字符时,str当前字符不变,pattern当前字符后移两位,跳过这个‘*’符号;
    • 当‘*’匹配1个或多个时,str当前字符移向下一个,pattern当前字符不变。(这里匹配1个或多个可以看成一种情况,因为:当匹配一个时,由于str移到了下一个字符,而pattern字符不变,就回到了上边的情况a;当匹配多于一个字符时,相当于从str的下一个字符继续开始匹配)

之后再写代码就很简单了。

递归代码

import java.util.Arrays;
public class Solution {
    public boolean match(char[] str, char[] pattern)
    {
        if(str == null || pattern == null)
            return true;
        //递归的思想
        return isMatch(str,0,pattern,0);
    }

    private  boolean isMatch(char[] str, int i, char[] pattern, int j) {
       if(j == pattern.length)//pattern遍历完了
            return str.length == i;//如果str也完了,返回true,不然false
       //注意数组越界问题,以下情况都保证数组不越界
        //下一个是*
       if(j < pattern.length - 1 && pattern[j + 1] == '*') {
           if(str.length != i && //当前匹配
                   (str[i] == pattern[j] || pattern[j] == '.')) //匹配
               return isMatch(str,i,pattern,j + 2) || isMatch(str,i + 1,pattern,j);
           else//当前不匹配
               return isMatch(str,i,pattern,j + 2);
       }
       //下一个不是“*”,当前匹配
       if(str.length != i && (str[i] == pattern[j] || pattern[j] == '.'))
           return isMatch(str,i + 1,pattern,j + 1);
       return false;
    }
}

解法二:动态规划

如果 pattern[j] == str[i] || pattern[j] == ‘.’,
此时dp[i][j] = dp[i-1][j-1];

如果 pattern[j] == ‘*‘
分两种情况:

1 如果pattern[j-1] != str[i] && pattern[j-1] != '.',此时dp[i][j] = dp[i][j-2] //a*匹配0次

2 如果pattern[j-1] == str[i] || pattern[j-1] == '.'
    此时dp[i][j] = dp[i][j-2] // a*匹配0次
    或者 dp[i][j] = dp[i][j-1] // a*匹配1次
    或者 dp[i][j] = dp[i-1][j] // a*匹配多次

代码

import java.util.Arrays;
public class Solution {
    public boolean match(char[] str, char[] pattern)
    {
        if(str == null || pattern == null)
            return true;
        //2 动态规划
        boolean[][] dp = new boolean[str.length + 1][pattern.length + 1];
        dp[0][0] = true;
        for (int i = 1; i < dp[0].length; i ++) {
            if(pattern[i - 1] == '*') dp[0][i] = dp[0][i - 2];
        }
        for (int i = 1; i < dp.length; i ++) {
            for (int j = 1; j < dp[0].length; j ++) {
                if(pattern[j - 1] == '.' || pattern[j - 1] == str[i - 1]) dp[i][j] = dp[i - 1][j - 1];
                else if(pattern[j - 1] == '*') {
                    if(pattern[j - 2] != str[i - 1] && pattern[j - 2] != '.') dp[i][j] = dp[i][j - 2];
                    else dp[i][j] = dp[i][j - 1] || dp[i][j - 2] || dp[i - 1][j];
                }
            }
        }
        return dp[str.length][pattern.length];
    }
}

文章作者: Hailong Gao
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Hailong Gao !
评论
  目录