leetcode 10 Regular Expression Matching

leetcode 10 Regular Expression Matching


题目描述:

Given an input string (s) and a pattern (p), implement regular expression matching with support for ‘.’ and ‘*’.

‘.’ Matches any single character.
‘*’ Matches zero or more of the preceding element.

The matching should cover the entire input string (not partial).

Note:

s could be empty and contains only lowercase letters a-z.
p could be empty and contains only lowercase letters a-z, and characters like . or *.
Example 1:

Input:
s = "aa"
p = "a"
Output: false
Explanation: "a" does not match the entire string "aa".
Example 2:

Input:
s = "aa"
p = "a*"
Output: true
Explanation: '*' means zero or more of the precedeng element, 'a'. Therefore, by repeating 'a' once, it becomes "aa".
Example 3:

Input:
s = "ab"
p = ".*"
Output: true
Explanation: ".*" means "zero or more (*) of any character (.)".
Example 4:

Input:
s = "aab"
p = "c*a*b"
Output: true
Explanation: c can be repeated 0 times, a can be repeated 1 time. Therefore it matches "aab".
Example 5:

Input:
s = "mississippi"
p = "mis*is*p*."
Output: false

题目理解:

进行正则表达式匹配,但与传统的匹配不同的是,*前面必须有字符存在,不能单独出现。
‘.’ 可以代表任何一个字符; ‘*’ 与之前的字符联用,代表可以有0个或多个前面的字符。
给定带匹配串s,模式串p,如果两个串满足正则匹配则返回true,否则返回false


我的思路:

因为存在‘*’,可以让前面的字符出现0次或者多次,而且只要有一种情况符合条件,就算匹配成功,这种选择可以有多种情况,每种都要考虑,不能通过单纯的遍历实现,这就让人联想到了回溯法。
但是我的问题是,即使问题的解决思路确认下来了,也写不对。。。
这是我的代码,不知道问题出在了哪里,先po上来,留给未来的自己(hhh)解决。

class Solution {
public:
    bool isMatch(string s, string p) {
        bool ans=false;
        judge(s,p,0,0,ans);
        return ans;
    }

void judge(string s,string p,int i,int j,bool &ans){
    if(ans == true) return;
    if(j>=p.size()){
        if(i==s.size()&&j==p.size()){
            ans = ans || true;
            return;
        }else{
            ans = ans || false;
            return;
        }
    }
    if(p[j+1]=='*'){
        if(p[j]==s[i]||p[j]=='.'&&s[i]!='\0'){
            judge(s,p,i,j+2,ans);
            judge(s,p,i+1,j,ans);
        }else{
            judge(s,p,i,j+2,ans);
        }
    }else if(s[i]==p[j]||s[j]=='.'&&s[i]!='\0'){
        judge(s,p,i+1,j+1,ans);
    }
}
};

错误信息:
这里写图片描述


然后因为自己实现不出来,就去寻找优秀代码,说实话这个题我磨蹭了很久,因为思路早早定下来,还自己实现不了就有些丧,最后还是跳了出来,学习优秀代码。下面就是学习到的回溯法,递归解决法。
这个方法是一个全递归的形式,与我通过两个整形下标遍历的方式不同,是通过对s和p串进行删减来进行比价的,每次比较时只局限在0,1下标上。

这里的递归有两种情况:
1.遇到‘*’:通过p[1]判断,如果是‘*’,可以选择不配陪直接跳过,即出现0次的情况(这种情况包括了*前面的字符与s串当前不匹配);也可以选择匹配一次,这时只动s串,如果满足匹配条件,将s串删掉已经匹配到一个。
2.没有‘*’:只比较当前的串头元素。相同就比较下一个。
当然,这里面的比较是递归形式的比较,当前条件是否满足&&剩下串里面是否满足(递归)

代码如下:

class Solution {
public:
    bool isMatch(string s, string p) {//通过substr,让每次的比较只集中在前两个字符
        if(p.empty()) return s.empty();
        if(p[1]=='*') return (isMatch(s,p.substr(2)) || ((p[0]==s[0]||p[0]=='.')&&!s.empty()&&isMatch(s.substr(1),p)));
        else return !s.empty()&&(p[0]==s[0]||p[0]=='.') && isMatch(s.substr(1),p.substr(1));
    }
};

在回溯法怎么解也解不出来的时候,我尝试过其他的思路,因为DP经典问题中有个最长子串的匹配问题,所以我就想这个题能否也用同样的思想可以解,当然自己想又没有想出来,看着别人的代码也看不太懂,就有些灰心,对DP法产生了一种莫名的恐惧(T^T)…

心情平复后,又读了一遍代码,然后突然感觉,DP法其实跟递归法很相似,就是将所有的递归情况提前存在了二维数组里面。但是从底向上,会与正面思维递归有些不一样。

class Solution {
public:
    bool isMatch(string s, string p) {
        int l1 = s.size();
        int l2 = p.size();
        vector<vector<bool>> dp(l1+1,vector<bool>(l2+1,false));
        dp[0][0] = true;//只有空串才能匹配空串
        for(int j=1;j<=l2;j++){
            dp[0][j] = j>1 && p[j-1]=='*'&&dp[0][j-2];
        }
        for(int i=1;i<=l1;i++){
            for(int j=1;j<=l2;j++){
                if(p[j-1]!='*'){
                    dp[i][j] = (s[i-1]==p[j-1]||p[j-1]=='.') && dp[i-1][j-1];
                }else{
                    dp[i][j] = (j>1&&dp[i][j-2]) || (s[i-1]==p[j-2]||p[j-2]=='.')&&dp[i-1][j];//这里i-1相当于递归时的i+1
                }
            }
        }
        return dp[l1][l2];
    }
};

不过总是感觉有些虚,需要做些DP专题训练。

猜你喜欢

转载自blog.csdn.net/qq_40280096/article/details/82117696