每日一题算法: 2020年6月20日 正则表达式匹配 isMatch(没做出来)

本文记录了一道关于正则表达式匹配的算法题,讲述了判断字符串s和模式p是否匹配的解题思路。作者探讨了处理*、.等特殊字符的策略,包括贪心算法的应用,以及在遇到特殊情况如.*时的处理方法。虽然最终未能完成代码,但分享了遇到的困难和对问题的深入理解。
摘要由CSDN通过智能技术生成

2020年6月20日 正则表达式匹配 isMatch

在这里插入图片描述

默认格式:

class Solution {
    public boolean isMatch(String s, String p) {

    }
}

解题思路:

这道题看起来不难,看完题目之后有的想法就是通过逻辑来循环判断是否符合,比如:

s=mississippi

p = mis*is*p*.

字符的话直接比较,相等继续,不相等的话直接返回false

然后是一个*,*的话长度不能确定,所以我们要先确定他的长度,如何确定他的长度,我们这里使用贪心算法,我直接找*后面的那个字符,在原字符串中查找在连续的该元素后是否存在字符i,如果存在,那么继续判断,如果不存在,那么返回false

后面这个*也是这么做判断,他找到自己的后一个元素是p而在上面连续寻找s之后得到的是i,不匹配,所以是错误的。

.的话就认为是一个通配符,匹配所有的字符。

这里有一个坑的点,就是在*后面继续跟原来的字符,比如这几种情况

坑1:

abcd*d

这种情况还是比较容易鉴别的,只需要判断前后加起来的长度是否超过上面的s中的长度就可以了,如果超过了,说明不匹配,如果没超过,那就和上面一样继续。

坑2:

abc.*d

如果出现了.*怎么办,貌似唯一的办法就是判断这个.*后面的字符串是否能和原字符串的末尾的一部分完全匹配。

最终的想法:

从p中循环读出字符,根据读出字符的不同进行不同的处理。当出现多种可能的时候,对字符串的所有可能进行递归处理。因为我找不到能够对可能出现的情况进行筛选的办法,任何试图对可能性进行删减的操作都有可能漏掉某一种正确可能性。

ps:

上面存在一个理解上的错误,a*b可以匹配ab,aab或者b,因为这个*表示的是前面那个字符的个数,可以是0个。

代码部分:

没能做出来,因为实在没能想到有什么能判别,.*.,这个格式方式,暴力破解也破解不了

没做出来,实在不行了,由于一开始的构思没构思好,做到后面整个算法过于复杂没办法修改,改一个地方就有另一个位置出错,最后实在是没有精力去改了,代码也写了很厚很厚,今天答案也不看了,太累了。

在这里插入图片描述

public boolean isMatch(String s, String p) {

        //字符串变成数组便于操作,可以使用getchar但是那个更消耗时间
        char[] charP=p.toCharArray();
        char[] charS=s.toCharArray();



        //indexP是当前处理P的字符的位置
        int indexP=0;
        //indexS是当前处理原数组S的位置
        int indexS=0;

        //主要循环
        for (;indexP<p.length()&&indexS<s.length();indexP++){

            //如果是点,表示是所有字符,此时会产生几种可能呢?
            if (charP[indexP]=='.'){

                //如果不是*,处理就很简单,直接让indexS++就可以了
                if (indexP+1<charP.length&&charP[indexP+1]!='*')
                {
                    indexS++;
                }
                //如果是*,那么就麻烦了,它可能代表了0-n个字符(n是charS剩余的长度-p的理论最小剩余长度),而且和*后面的一个字符一样
                else if (indexP+1<charP.length)
                {
                    //.*也分为两种,.*.和.*a这两种

                    //如果是.*a这种格式的
                    if(indexP+2<charP.length&&charP[indexP]!='.'){

                        //在原字符串中寻找和.*后的那个字符相同的字符
                        for(int i=indexS;i<s.length();i++){

                            //如果相同的,那么递归一下判断是否完全一致
                            if (charS[i]==charP[indexP+2]){
                                String s1=new String(charS,i,s.length()-i);
                                String p1=new String(charP,indexP+2,p.length()-indexP-2);
                                //如果通过了,返回true
                                if(isMatch(s1,p1)){
                                    return true;
                                }
                            }
                        }

                        //如果所有可能都判断完了,那么就不可能相等了
                        return false;
                    }
                    else if(indexP+2<charP.length){
                        //如果是.,那么就不用判断是否相等了,因为.代表了所有的字符
                        for(int i=indexS;i<s.length();i++){
                            String s1=new String(charS,i,s.length()-i);
                            String p1=new String(charP,indexP+2,p.length()-indexP-2);
                            //如果通过了,返回true
                            if(isMatch(s1,p1)){
                                return true;
                            }
                        }
                        //如果所有可能都判断完了,那么就不可能相等了
                        return false;
                    }
                    //如果长度不够,说明以.*结尾,直接输出true
                    else
                        return true;


                }
                else
                    indexS++;

            }
            //如果是*,那么是和前一个字符相关的,先获取前一个字符
            else if (charP[indexP]=='*'){

                //可以直接获取上一个的值,因为规定了不会在首位出现*,而且经过我的处理,前面一个不会是.,所以可以直接认为是一个字符
                char previous=charP[indexP-1];
                //只要是a*这种格式的,原式中每一个a就会产生一个递归判断
                for (;((indexS-1)<s.length()&&charS[indexS-1]==previous);indexS++){
                    String s1=new String(charS,indexS-1,s.length()-indexS+1);
                    String p1=new String(charP,indexP+1,p.length()-indexP-1);
                    if(isMatch(s1,p1)){
                        return true;
                    }
                }
                String s1=new String(charS,indexS-1,s.length()-indexS+1);
                String p1=new String(charP,indexP+1,p.length()-indexP-1);
                if(isMatch(s1,p1)){
                    return true;
                }
                return false;
            }
            else {
                //单纯字符的话直接比较字符是否相等
                    if (charP[indexP]==charS[indexS])
                    {
                        indexS++;
                    }
                    //如果不相等但是下一个字符是*,则表示*=0不存在该字符的,此时p的下标需要移动两格
                    else if(indexP+1<charP.length&&charP[indexP+1]=='*'){
                        indexP++;
                    }
                    else
                        //不相等返回false
                        return false;
            }

        }

        //循环结束没有问题,判断普通字符串是否到达末尾,这是必要条件
        if (indexS==s.length()){
            //两个都到达末尾,表示真正的结束
            if (indexP==p.length())
                return true;
            //如果正则的没到到末尾,判断一下剩下的部分是否实际长度为0,如果为0,也是到达了末尾
            else {
                int num = 0;
                for (int i=indexP; i < p.length(); i++) {

                    //如果有一个*,则最小长度-1,否则+1
                    if (charP[i] == '*')
                        num--;
                    else
                        num++;
                }
                if (num>0)
                    return false;
                if (charP[p.length()-1]=='*'&&num <= 0) {
                    //查看p的剩余长度是否小于等于0
                        return true;
                }
                else if (charP[p.length()-1]==charP[indexP-1]&&num <= 0){
                    return true;
                }
                else
                    return false;
            }
        }
        return false;

    }

感觉写出来也是很慢的样子,直接贴官方答案吧

class Solution {
    public boolean isMatch(String s, String p) {
        int m = s.length();
        int n = p.length();

        boolean[][] f = new boolean[m + 1][n + 1];
        f[0][0] = true;
        for (int i = 0; i <= m; ++i) {
            for (int j = 1; j <= n; ++j) {
                if (p.charAt(j - 1) == '*') {
                    f[i][j] = f[i][j - 2];
                    if (matches(s, p, i, j - 1)) {
                        f[i][j] = f[i][j] || f[i - 1][j];
                    }
                }
                else {
                    if (matches(s, p, i, j)) {
                        f[i][j] = f[i - 1][j - 1];
                    }
                }
            }
        }
        return f[m][n];
    }

    public boolean matches(String s, String p, int i, int j) {
        if (i == 0) {
            return false;
        }
        if (p.charAt(j - 1) == '.') {
            return true;
        }
        return s.charAt(i - 1) == p.charAt(j - 1);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值