[leetcode] 10. Regular Expression Matching

Description

Given an input string (s) and a pattern §, 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

分析

题目的意思是:

动态规划
dp[i][j]表示s[i-1]与p[j-1]是否匹配
如果 p[j-1] == s[i-1] || p[j-1] == ‘.’, 此时dp[i][j] = dp[i-1][j-1];
如果 p[j-1] == ‘*’
分两种情况:
1: 如果p[j-2] != s[i-1] && p[j-2] != ‘.’, 此时dp[i][j] = dp[i][j-2] //*前面字符匹配0次
2: 如果p[j-2] == s[i-1] || p[j-2] == ‘.’
此时dp[i][j] = dp[i][j-2] // *前面字符匹配0次
或者 dp[i][j] = dp[i][j-1] // *前面字符匹配1次
或者 dp[i][j] = dp[i-1][j] // *前面字符匹配多次

这题用递归的话,大致思路如下:

  1. 若p为空,s也为空,则返回true,否则返回false;
  2. 若p的长度为1,s的长度也为1,且相同或p为‘.’,则返回true,否则返回false;
  3. 若p的第二个字符不为*,此时s为空,则返回false,否则判断首字符是否匹配,且从各自的第二个字符开始调用递归函数;
  4. 若p的第二个字符为*,若s不空且字符匹配,调用递归函数s和去掉前两个字符的p,若匹配,则返回true,否则s去掉首字母;
  5. 返回调用递归函数匹配s和去掉前两个字符p的结果。

代码一 递归版本

class Solution {
public:
    bool isMatch(string s, string p) {
        if(p.empty()) return s.empty();
        if(p.size()==1){
            return s.size()==1&&(s[0]==p[0]||p[0]=='.');
        }
        if(p[1]!='*'){
            if(s.empty()) return false;
            return (s[0]==p[0]||p[0]=='.')&&isMatch(s.substr(1),p.substr(1));
        }
        while(!s.empty()&&(s[0]==p[0]||p[0]=='.')){
            if(isMatch(s,p.substr(2))) return true;
            s=s.substr(1);
        }
        return isMatch(s,p.substr(2));
    }
};

代码二 动态规划版本

class Solution {
public:
    bool isMatch(const char *s, const char *p) {
        int m=strlen(s);
        int n=strlen(p);
        if(m==0&&n==0){
            return true;
        }
        bool dp[m+1][n+1];
        memset(dp,false,sizeof(dp));
        dp[0][0]=true;
        for(int i=1;i<=n;i++){
            if(p[i-1]=='*'){
                dp[0][i]=dp[0][i-2];
            }
        }
        for(int i=1;i<=m;i++){
            for(int j=1;j<=n;j++){
                if(s[i-1]==p[j-1]||p[j-1]=='.'){
                    dp[i][j]=dp[i-1][j-1];
                }else if(p[j-1]=='*'){
                    if(j!=1&&p[j-2]!='.'&&s[i-1]!=p[j-2]){
                        dp[i][j]=dp[i][j-2];
                    }else{
                        dp[i][j]=dp[i][j-1]||dp[i-1][j]||dp[i][j-2];
                    }
                }
            }
        }
        return dp[m][n];
    }
};

Python实现

这个动态规划写出来要处理’.‘和’*'两种情况。

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        m = len(s)
        n = len(p)
        dp =[[False]*(n+1) for _ in range(m+1)]
        dp[0][0]=True
        for i in range(1,n+1):
            if p[i-1]=="*":
                dp[0][i]=dp[0][i-2]

        for i in range(1, m+1):
            for j in range(1, n+1):
                if s[i-1]==p[j-1] or p[j-1]=='.':
                    dp[i][j]=dp[i-1][j-1]
                elif p[j-1]=="*":
                    if j>1 and p[j-2]!='.' and s[i-1]!=p[j-2]:
                        dp[i][j]=dp[i][j-2]
                    else:
                        dp[i][j]=dp[i][j-1] or dp[i-1][j] or dp[i][j-2]
        return dp[m][n]

参考文献

[编程题]regular-expression-matching
[LeetCode] Regular Expression Matching 正则表达式匹配

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

农民小飞侠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值