JZ19 正则表达式匹配

请实现一个函数用来匹配包括'.'和'*'的正则表达式。

1.模式中的字符'.'表示任意一个字符

2.模式中的字符'*'表示它前面的字符可以出现任意次(包含0次)。

在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配

数据范围:

1.str 只包含从 a-z 的小写字母。

2.pattern 只包含从 a-z 的小写字母以及字符 . 和 *,无连续的 '*'。

3. 0 \le str.length \le 26 \0≤str.length≤26 
4. 0 \le pattern.length \le 26 \0≤pattern.length≤26

分析如下:

/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 * 
 * @param str string字符串 
 * @param pattern string字符串 
 * @return bool布尔型
 */
bool match(char* str, char* pattern ) {
    if(str == NULL || pattern == NULL){
        return false;
    }
    if(*str == '\0' && *pattern == '\0'){
        return true;
    }else if(str[0] == 0 && pattern[0] != 0){
        if(pattern[1] == '*'){
            return match(str, pattern+2);
        }else{
            return false;
        }
    }else if(str[0] != 0 && pattern[0] == 0){
        return false;
    }
    if(*pattern == *str){
        if(pattern[1] == '*'){
            return match(str+1, pattern) || match(str, pattern+2);
        }else{
            return match(str+1, pattern+1);
        }
    }else if(pattern[0] == '.'){
        if(pattern[1] == '*'){
            return match(str+1, pattern) || match(str, pattern+2);
        }else{
            return match(str+1, pattern+1);
        }
    }else{
        if(pattern[1] == '*'){
            return match(str, pattern+2) ;
        }else{
            return false;
        }
    }
}

使用递归更容易理解。首先对输入进行判断,如果有空指针返回false。然后寻找结束递归的条件,如果两个字符串同时到达最后'\0',则认为是适配成功的。如果非正则为0,正则不为0,有可能是a*这种情形,将pattern加2后再次进行适配。但是如果pattern == 0,str != 0,则肯定是不匹配的。结束递归的条件确定,进入正式逻辑

        1.如果*pattern == *str。要考虑到aaaaa,a*的情况,这种情况match(str+1, pattern)这样处理。直到最后*str == 0,然后将a*忽略这样的逻辑。也可能bd和a*bd,此时就是match(str, pattern+2)。如果pattern[1]  != '*',则将两个字符串都加1。

        2.如果*pattern == '.' 。此时逻辑与上面相同

        3.说明当前字符确实不匹配,这种情形只有一种情况可能返回true,即pattern[1]  == '*',使用match(str, pattern+2)再次进行匹配。

以上全部为或逻辑,即只要有一种匹配方式为true,则表明正则表达式可以表示。

下面为《剑指offer》题解,里面回溯场景考虑重复,导致时间较长。时间为465 ms,上述方法为15 ms。多了一个match(str+1, pattern+2),为了解决ab和a*b这种情形,其实这种情形可以用match(str+1, pattern)来解决,变成b和a*b,再变成b和b。

/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 * 
 * @param str string字符串 
 * @param pattern string字符串 
 * @return bool布尔型
 *
 * C语言声明定义全局变量请加上static,防止重复定义
 */
int match_core(char* str, char* pattern){
    if(str[0] == '\0' && pattern[0] == '\0'){
        return 1;
    }
    if(str[0] != '\0' && pattern[0] == '\0'){
        return 0;
    }
    if(pattern[1] == '*'){
        if(pattern[0] == str[0] || (pattern[0] == '.' && str[0] != 0 )){
             return match_core(str+1, pattern+2) ||
                   match_core(str+1, pattern)   ||
                   match_core(str, pattern+2);
        }else{
            return match_core(str, pattern+2);
        }
    }
    if(str[0] == pattern[0] || (pattern[0] == '.' && str[0] != 0 )){
        return match_core(str + 1, pattern+1);
    }
    return 0;
}

int match(char* str, char* pattern ) {
    if(str == NULL || pattern == NULL) {
        return 0;
    }
    return match_core(str, pattern);
}

————————————————————————-——————————

这种递归解法其实算是暴力破解,里面多次计算了一些子问题,可以使用动态规划来进行求解,递推式非常难找,参考LeetCode

#include <string>
#include <vector>
class Solution {
public:
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     * 
     * @param str string字符串 
     * @param pattern string字符串 
     * @return bool布尔型
     */
    
    bool is_match(string s, string p, int i, int j){
        if(i == 0)
            return false;
        if(p[j-1] == '.'){
            return true;
        }
        return s[i-1] == p[j-1];
    }
    bool match(string str, string pattern) {
        int len1 = str.length(), len2 = pattern.length();
        vector<vector <int>> mark(len1+1, vector<int>(len2+1));
        mark[0][0] = true;
        for(int i = 0 ; i <= len1 ; i++){
            for(int j = 1; j <= len2; j++){
                if(pattern[j-1] == '*'){
                    mark[i][j] = mark[i][j-2];
                    if(is_match(str, pattern, i,  j-1)){
                        mark[i][j] = mark[i][j] || mark[i-1][j];
                    }
                }else{
                    if(is_match(str, pattern, i, j)){
                        mark[i][j] = mark[i-1][j-1];
                    }
                }
            }
        }
        return mark[len1][len2];
    }
};

如果是c语言就用二维数组代替vector,但是由于数组不能动态定义,所以写起来有点麻烦。

is_match表示第i个和第j个是否匹配,即s[i-1]和p[j-1]

mark[i][j]表示前i个和前j个字符是否匹配,p[j-1]代表第j个字符

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值