LC10. 正则表达式匹配

题目

给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 ‘.’ 和 ‘*’ 的正则表达式匹配。

'.' 匹配任意单个字符
'*' 匹配零个或多个前面的那一个元素

所谓匹配,是要涵盖整个字符串s的,而不是部分字符串。
提示:

1 <= s.length <= 20
1 <= p.length <= 30
s 只含小写英文字母。
p 只含小写英文字母,以及字符 . 和 *。
保证每次出现字符 * 时,前面都匹配到有效的字符

思路

  • 题目中要求s与p正则表达式匹配,实际是指p经过正则表达式表示后字符串的某一种可能性与s字符串的字符刚好一一对应。(第一次提交没理解,报错)
  • “ * ” 需要与前面一字符融为一体。以 “a*”为例,匹配零个或多个前面的那一个元素指的是"a*"表达式可能含有0个a,也可能含有多个a。即a*含有n个a(0<=n)。

此时最直接的办法是,将p字符串的所有种情况枚举出来(主要是*可能产生的字符的数量),然后与s进行对比,如果有一种可能性两字符串刚好相等,则可输出true。
但此时我们可以发现,枚举每一种可能性时,中间可能出现重复部分(即p字符串中某些字段可能在不同可能性中均含有,会出现计算现象)。此时动态规划便可以引出来应用。

在长度为len的p字符串中,他的最好的一种表达结果是与s相同,比如

s="asdf", p="asd."
即当.为f时,p与s相同
但前提是.前面的asd字符段需要与s前面的也相等

因此字符串索引值靠后的表达结果受到他前面结果的影响
所以此时动态规划需要从字符串左向右进行,因此存储前面的状态(标记现在为止是否与s字符串一致)

我们可以建立一个二维数组f存储状态,f[i][j]表示s的前i个元素是否和p的前j个元素一致。(注意:s[i-1]是s第i个元素,p[j-1]是p第j个状态,写代码时不要混淆。至于为什么不将设置为i、j代表s、p的i、j下标之前的元素,后面会讲)
此时我们需要考虑两种情况:

  • p[j-1]不等于"*"
  • p[j-1]等于"*"

1、 当 p[j-1]不是“*”,分为两种情况:

  • p[j-1]和s[i-1]相等或者p[j-1]为".":他们能保证当前元素相同,但还需知道前面元素是否一致。即需要参考f[i-1][j-1]的状态,如果前面的状态是与s不匹配的,那在这个位置f[i][j]也是不能匹配的,为false。

  • 不是上述情况:说明此时元素不匹配s[i-1]!=p[j-1],则f[i][j]状态应该代表不匹配,为false

    状态方程如下:
    在这里插入图片描述

2、当 p[j-1]是“*”,分为两种情况:

  • p[j-2]和s[i-1]不相等,此时“*”代表0个前一字符。相当于p[j-1]与p[j-2]相当于空气,并不存在。所以此时f[i][j] 的状态应该和f[i][j-2]一致(即p的前j-2个字符,到p[j-3]为止)

  • p[j-2]和s[i-1]相等或者p[j-2]为".",因为“*”可以表示0或者多个前一字符,所以这里又分为两种情况:

    • “*”表示0个字符:此时同p[j-2]和s[i-1]不相等一样,p[j-1]与p[j-2]相当于空气。此时f[i][j] 的状态应该和f[i][j-2]一致
    • “*”表示多个字符:
      • 当 "*"表示一个字符时(如“a*”表示“a”):​f[i][j]=f[i−1][j]
      • 当 "*"表示2个字符时(如“a*”表示“aa”):​f[i][j]=f[i−2][j]
      • 当 "*"表示3字符时(如“a*”表示“aaa”):​f[i][j]=f[i−3][j]
      • 此时要分好多种情况,比较复杂,但是我们可以发现规律:因为j是定值,所以对于i-n(i-1>=n>=0),有f[i-n][j]受到f[i-n-1][j]的影响,说明只要f[1][j]状态匹配,f[i][j]则都匹配。所以f[i][j]与f[i-1][j]状态相关,与f[1][j]状态也相关。
    • 因为“*”有这么多种情况,所以只要有一种情况能匹配就满足要求,因此f[i][j]状态可以取上述情况的或情况

    状态方程如下:
    在这里插入图片描述

我们可以发现,里面有i-1,j-2,如果将i、j设为下标,数组访问会出现溢出现象。因此我们需要从1开始。
因为每一个状态都需要前面状态决定,所以在f[i][j]中,i=0的行和j=0的列是本题动态规划的起点。我们也需要对其进行初始化

  • 首先将f[0][0]设为true,因为此时的意思是s的前0个元素和p的前0个元素是否匹配,既然都没有元素,那肯定是匹配的,所以设为true
  • f[0][j]其他元素:此时的意思是s的前0个元素和p的前j个元素是否匹配,s此时没有元素要匹配,p[j]只要有元素,都不是和s匹配的,需要设为false。但是含“*”的位置可代表0个元素,所以是可以和此时没有元素的s匹配。此判断过程可以和上面s和p内元素匹配程序合并。
  • f[i][0](此处i>0):因为此时的意思是s的前i个元素和p的前0个元素是否匹配,因此p中此时没有元素所以不可能匹配,全都为false(0)。初始化数组时就建立了,无需重新赋值。

代码

class Solution {
public:
    bool isMatch(string s, string p) {
        int len1 = s.size(), len2 = p.size();
        vector<vector<int>> f(len1+1, vector<int>(len2+1));

        auto match = [&](int i, int j){
            if(i==0) 
                return false;
            if(s[i-1]==p[j-1]||p[j-1]=='.')
                return true;
            else 
                return false;
        };

        f[0][0] = true;
        
        for(int i=0;i<=len1;i++){
            for(int j=1;j<=len2;j++){
                if(p[j-1]=='*'){
                    if(match(i, j-1))
                        f[i][j] = f[i-1][j];
                    f[i][j] |= f[i][j-2];
                }
                else if(match(i, j))
                    f[i][j] = f[i-1][j-1];
                else
                    f[i][j] = false;
            }
        }
        return f[len1][len2];
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为您提供一个综合校验油车和电车牌号的正则表达式: ``` ^(?![DFIOQU])[A-HJ-PR-Z][A-HJ-NP-Z\d]\d{4}(?<!ad|am|ap|az|cd|cm|cp|cz|dd|dm|dp|dz|ea|eb|ec|ed|ef|eg|eh|ej|el|em|en|ep|eq|er|es|et|ev|ew|ex|ey|ez|fd|ff|fg|fh|fj|fk|fl|fm|fn|fp|fq|fr|fs|ft|fv|fw|fx|fy|fz|gd|gf|gg|gh|gj|gk|gl|gm|gn|gp|gq|gr|gs|gt|gv|gw|gx|gy|gz|ha|hb|hc|hd|he|hf|hg|hh|hj|hk|hl|hm|hn|hp|hq|hr|ht|hv|hw|hx|hy|hz|ia|ib|ic|id|ie|if|ig|ih|ij|ik|il|im|in|io|ip|iq|ir|is|it|iv|iw|ix|iy|iz|jd|jf|jg|jh|jj|jk|jl|jm|jn|jp|jq|jr|js|jt|jv|jw|jx|jy|jz|ka|kb|kc|kd|ke|kf|kg|kh|kj|kk|kl|km|kn|kp|kq|kr|ks|kt|kv|kw|kx|ky|kz|la|lb|lc|ld|le|lf|lg|lh|lj|lk|ll|lm|ln|lp|lq|lr|ls|lt|lv|lw|lx|ly|lz|mm|mn|mp|mz|na|nb|nc|nd|ne|nf|ng|nh|nj|nk|nl|nm|nn|np|nq|nr|ns|nt|nv|nw|nx|ny|nz|pa|pb|pc|pd|pe|pf|pg|ph|pj|pk|pl|pm|pn|pp|pq|pr|ps|pt|pv|pw|px|py|pz|qa|qb|qc|qd|qe|qf|qg|qh|qj|qk|ql|qm|qn|qp|qq|qr|qs|qt|qv|qw|qx|qy|qz|ra|rb|rc|rd|re|rf|rg|rh|rj|rk|rl|rm|rn|rp|rq|rr|rs|rt|rv|rw|rx|ry|rz|sa|sb|sc|sd|se|sf|sg|sh|sj|sk|sl|sm|sn|sp|sq|sr|ss|st|sv|sw|sx|sy|sz|ta|tb|tc|td|te|tf|tg|th|tj|tk|tl|tm|tn|tp|tq|tr|ts|tt|tv|tw|tx|ty|tz|ua|ub|uc|ud|ue|uf|ug|uh|uj|uk|ul|um|un|uo|up|uq|ur|us|ut|uv|uw|ux|uy|uz|va|vb|vc|vd|ve|vf|vg|vh|vj|vk|vl|vm|vn|vp|vq|vr|vs|vt|vu|vv|vw|vx|vy|vz|wa|wb|wc|wd|we|wf|wg|wh|wj|wk|wl|wm|wn|wp|wq|wr|ws|wt|wv|ww|wx|wy|wz|xa|xb|xc|xd|xe|xf|xg|xh|xj|xk|xl|xm|xn|xp|xq|xr|xs|xt|xv|xw|xx|xy|xz|ya|yb|yc|yd|ye|yf|yg|yh|yj|yk|yl|ym|yn|yo|yp|yq|yr|ys|yt|yv|yw|yx|yy|yz|za|zb|zc|zd|ze|zf|zg|zh|zj|zk|zl|zm|zn|zo|zp|zq|zr|zs|zt|zv|zw|zx|zy)[DFIOQU]$ ``` 此正则表达式可以用于校验6位车牌号,包括油车和电车,但是不包括以"AD","AM","AP","AZ","CD"等开头的车牌号。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值