leetcode模式匹配算法

12 篇文章 0 订阅
11 篇文章 0 订阅

题目出处

  https://leetcode.com/problems/regular-expression-matching/

  实现简单的正则表达式算法,正则表达式中支持".", "*"两个特殊字符, 并实现整个字符串匹配。

  ".": 表示任意一个字符。

 "*": 表示任意多个个前一个字符。

例: 

isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "a*") → true
isMatch("aa", ".*") → true
isMatch("ab", ".*") → true
isMatch("aab", "c*a*b") → true

分析

注意到根据长度可以把正则表达式分为两种形式:

   固定长度的子字符串:

如"c*a*b" 表达式中就是 “b" 长度固定为1.

子字符串中也包含特殊字符"."

   可变长度的模式子字符串: 组成的都是长度不固定的子字符串。

如"c*a*b" 表达式中就是 “c*a*" 长度不固定,并且长度可以是0.

子字符串的形式为: 多个{a}*相边, {a}变量可以是任意字符,也可以是特殊字符", "。 

注意到如果索引从1开始的话,子串的偶数位必须是特殊字符"*"


把表达式按这个规则分成子串列表,则必然是上面两种形式的子串交替进行。可递归实现此算法。


算法:

1. 分解输入的正则表达式,获得子模式列表。

2. 如果是可变模式时,尝试逐个判断, 进行递归。具体可看代码实现


3. 如果是固定子模式时,位置可直接判断


代码实现

为了便于阅读,分解了几个功能函数来处理。

1.分解表达式

vector<string> parsePattern(string p){
        vector<string> p_vector;
        int start = 0;
        for(int i = 1; i < p.length(); i++){

            if(p[i] != '*')continue;
            //添加固定项
            if(i - start >1)
                p_vector.push_back(p.substr(start, i-1-start));
            //查找下一个两个的数字 寻找a*b*c*模式的结束点
            int j = i+2;
            while(j < p.length() && p[j]== '*') j += 2;
            p_vector.push_back(p.substr(i-1, j-i)); //加入子模糊模式 a*b*c*
            start = i = j-1;
        }
        if(start < p.length())
            p_vector.push_back(p.substr(start));
        return p_vector;
    }
2. 检查一个固定模式是否匹配

//检查固定的数据
    bool check(string &s, int start, int end, string p){
       if(end-start != p.length()) return false;
       for(int i = 0; i < p.length(); i++)
            if(p[i] != '.' && p[i] != s[start+i]) return false;
       return true;
    }

3. 检查可变模式是否匹配
// 检查长度不固定的模式
    bool checkMode(string &s, int start, int end, string p){
        if(start == end || p.find(".*") != string::npos) return true;
        for(int i = 0; i < p.length(); i+= 2){
            while(start < end && s[start] == p[i]) start++;
            if(start >= end) return true;
        }
        return (start >= end);
    }

4. 处理子模式列表中的第pi个模式匹配

bool checkVector(string &s, int start, int end, vector<string> &p, int pi){ 
        
        if(p.size() <= pi)return start == end; 
        
        if(p[pi].length() > 1 && p[pi][1] == '*'){
            
            //为了下速处理,对可变模式当前位于最后,或倒数第二位时作特殊处理
            //就有了下面的两个if语句,节省代码可直接去掉,,不影响结果。
            if(pi+2 == p.size()){
                if(start + p[pi+1].length() > end) return false;
                if(!check(s, end-p[pi+1].length(), end, p[pi+1]))return false;
                end -= p[pi+1].length();
            }
            if(pi+2 >= p.size()) return checkMode(s, start, end, p[pi]);
            //由于未处理的模式长度大于2时才会走到这里,所以p[pi+1].length() 就不需要判断是否超界
            //如果前面没作优化,则需要判断
            for(int i = start; i + p[pi+1].length() <= end; i++){
                if(!checkMode(s, start, i, p[pi])) return false;
                if(checkVector(s, i, end, p, pi+1))return true;
            }
            return false;
        } 
        if(end - start < p[pi].length()) return false;
        if(!check(s, start, start + p[pi].length(), p[pi]))return false;
        start += p[pi].length(); 
        return checkVector(s, start, end, p, pi+1);

    }

5. 对外接口函数

bool isMatch(string s, string p){
        if(s == p) return true;
        if(p == "" && s != "") return false; 
        //分解格式
        vector<string> p_vector = parsePattern(p); 
        return checkVector(s, 0, s.length(), p_vector, 0);
    }



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值