列表

详情


DP21. 正则表达式匹配

描述

请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配

数据范围:
1.str 只包含从 a-z 的小写字母。
2.pattern 只包含从 a-z 的小写字母以及字符 . 和 *,无连续的 '*'。
3.
4.

输入描述

第一行输入一个字符串 str。
第二行输入一个字符串 pattern。    

输出描述

输出两个字符串的匹配结果,如果匹配则输出 true ,否则输出 false

示例1

输入:

aaa
a*a

输出:

true

示例2

输入:

aab
c*a*b

输出:

true

示例3

输入:

a
.*

输出:

true

示例4

输入:

aaab
a*a*a*c

输出:

false

原站题解

C 解法, 执行用时: 2ms, 内存消耗: 348KB, 提交时间: 2022-07-09

#include <stdio.h>

int main(){
    char str[1000];
    char pattern[1000];
    int n = 0,m = 0,i = 0,j = 0;
    scanf("%s",str);
    scanf("%s",pattern);
    n = strlen(str);
    m = strlen(pattern);
    int dp[n+1][m+1];
    for(i = 0; i <= n; i++){
        for(j = 0; j <= m; j++){
            dp[i][j] = 0;
        }
    }
    for(i = 0; i <= n; i++){
        for(j = 0; j <= m; j++){
            if(j == 0){
                dp[i][j] = (i == 0 ? 1 : 0);
            }
            else{
                if(pattern[j-1] != '*'){
                    if(i > 0 && (str[i-1] == pattern[j-1] || pattern[j-1] == '.')){
                        dp[i][j] = dp[i-1][j-1];
                    }
                }
                else{
                    if(j >= 2){
                        dp[i][j] |= dp[i][j-2];
                    }
                    if(i >= 1 && j >= 2 && (str[i-1] == pattern[j-2] || pattern[j-2] == '.')){
                        dp[i][j] |= dp[i-1][j];
                    }
                }
            }
        }
    }
    printf("%s",dp[n][m] == 1 ? "true" : "false");
//     printf("%d",dp[n][m]);
    return 0;
}

C++ 解法, 执行用时: 3ms, 内存消耗: 408KB, 提交时间: 2022-07-09

// #include<bits/stdc++.h>
#include <iostream>
#include <vector>

using namespace std;

int solve(string &s1, string &s2, int i, int j, vector<vector<int>> &dp);
int solve3(string &s1, string &s2);

int main(){
    string s1, s2;
    cin >> s1;
    cin >> s2;
    vector<vector<int>> dp(s1.size(), vector<int>(s2.size(),-1));
    int flag = solve(s1,s2,s1.size()-1,s2.size()-1,dp);
    flag ? cout << "true" << endl : cout << "false" <<endl;
    return 0;
}

int solve(string &s1, string &s2, int i, int j, vector<vector<int>> &dp){
    
    if(i < 0 ){//贪婪匹配后,造成str被用完。
      //只需要剩下部分满足字母+*的组合就匹配成功
        int flag = 1;
        for(int l = 0; l <= j; l+=2){
            if (s2[l] != '*' && s2[l+1] == '*')continue;
            else flag = 0;
        }
        return flag;
    }
    if(dp[i][j] != -1) return dp[i][j];
    if(i == 0 && j == 0){//两边只剩一个点的匹配,'.'可以匹配任何字符,要么两边为同一个字符。
        if(s2[j] == '.' || s2[j] == s1[i]) dp[i][j] = 1;
        else dp[i][j] = 0;
    }
    else{//当前字符匹配成功后,结果只和前值有关
        if(s1[i] == s2[j] || s2[j] == '.') dp[i][j] = solve(s1, s2, i-1, j-1, dp);
      //如果遇见‘*’号则进行贪婪匹配或者0次匹配。
        else if(s2[j] == '*') dp[i][j] = ((s1[i] == s2[j-1] || s2[j-1] == '.') && solve(s1, s2, i-1, j, dp)) || solve(s1, s2, i, j-2, dp);
        else dp[i][j] = 0;
    }
    return dp[i][j];
}

int solve3(string &s1, string &s2){//递推
    vector<vector<int>> dp(s1.size(), vector<int>(s2.size()));
    dp[0][0] = (s1[0] == s2[0] || s2[0] == '.');
    if(s2[1] == '.' || s2[1] == s1[0]) dp[0][1] = 1 - dp[0][0];
    else if(s2[1] == '*') dp[0][1] = dp[0][0];
    for(int j = 2; j < s2.size(); ++j){//初始化i=0行
        if( s2[j] =='.' || s2[j] == s1[0]) {
            int flag = 0;
            for(int l = 1; l <= j; l+= 2){
                if (s2[l] != '*'){
                    flag = 1;
                    break;
                }
            }
            dp[0][j] = 1 - flag;
        }
        else if(s2[j] == '*'){
            dp[0][j] = dp[0][j-1] || dp[0][j-2];
        }
    }
    for(int i = 1; i < s1.size(); ++i){//一般情况,遇到*号时,分匹配还是不匹配做出选择。
        for(int j = 1; j < s2.size(); ++j){
            if (s2[j] == '.' || s2[j] == s1[i]) dp[i][j] = dp[i-1][j-1];
            else if(s2[j] =='*') dp[i][j] = (dp[i-1][j] && (s2[j-1] == s1[i] || s2[j-1] == '.')) || (j>=2? dp[i][j-2]:0);
        }
    }
    return dp[s1.size()-1][s2.size()-1];
}

C 解法, 执行用时: 3ms, 内存消耗: 408KB, 提交时间: 2022-06-21

#include <stdio.h>
#include <stdbool.h>

int main() {
    char str[1001] = "", pattern[1001] = "";
    scanf("%s", str);
    scanf("%s", pattern);
    
    int sLen = strlen(str), pLen = strlen(pattern);
    bool **dp = (bool **)malloc(sizeof(bool *) * (sLen + 1));
    for (int i = 0; i < sLen + 1; i++) {
        dp[i] = (bool *)malloc(sizeof(bool) * (pLen + 1));
        memset(dp[i], 0, sizeof(bool) * (pLen + 1));
    }

    dp[0][0] = true;
    for (int j = 2; j < pLen + 1; j+=2) {
        if (pattern[j-1] == '*') {
            dp[0][j] = true;
        } else {
            break;
        }
    }
    for (int i = 1; i < sLen + 1; i++) {
        dp[i][0] = false;
        for (int j = 1; j < pLen + 1; j++) {
            if (pattern[j-1] == '.') {
                dp[i][j] = dp[i-1][j-1];
            } else if (pattern[j-1] == '*') {
                if (str[i-1] == pattern[j-2] || pattern[j-2] == '.') {
                    dp[i][j] = dp[i-1][j] || dp[i][j-2];
                } else {
                    dp[i][j] = dp[i][j-2];
                }
            } else {
                if (str[i-1] == pattern[j-1]) {
                    dp[i][j] = dp[i-1][j-1];
                } else {
                    dp[i][j] = false;
                }
            }
        }
    }
    
    if (dp[sLen][pLen]) {
        printf("true");
    } else {
        printf("false");
    }
    
    for (int i = 0; i < sLen + 1; i++) {
        free(dp[i]);
    }
    free(dp);
    
    return 0;
}




C++ 解法, 执行用时: 3ms, 内存消耗: 444KB, 提交时间: 2022-05-13

#include <iostream>
#include <cstring>
using namespace std;

#define MAX_N 1005



int main() {
    string s1, s2;
    cin >> s1 >> s2;
    int len1 = s1.size();
    int len2 = s2.size();
    bool dp[len1 + 1][len2 + 1];
    for (int i = 0; i <= len1; i++) {
        for (int j = 0; j <= len2; j++) 
            dp[i][j] = false;
    }
    
    // 初始化
    dp[0][0] = true;
    for (int i = 1; i <= len2; i++) {
        if (s2[i - 1] == '*') 
            dp[0][i] = dp[0][i - 2];  
    }
    
    for (int i = 1; i <= len1; i++) {
        for (int j = 1; j <= len2; j++) {
            if (s2[j - 1] == '*') {
                if (s2[j - 2] == '.' || s2[j - 2] == s1[i - 1]) 
                    dp[i][j] = dp[i - 1][j] || dp[i][j - 1] || dp[i][j - 2];
                else 
                    dp[i][j] = dp[i][j - 2];
            } 
            else {
                if (s2[j - 1] == '.' || s2[j - 1] == s1[i - 1]) 
                    dp[i][j] = dp[i - 1][j - 1];
            }
        }
    }
    
    if (dp[len1][len2]) 
        cout << "true" << endl;
    else 
        cout << "false" << endl;
    
    
    return 0;
}

C++ 解法, 执行用时: 3ms, 内存消耗: 452KB, 提交时间: 2022-03-31

#include<bits/stdc++.h>
using namespace std;
int main(){
    string s,p;
    cin>>s>>p;
    vector<vector<bool>> dp(s.size()+1,vector<bool>(p.size()+1,false));
    dp[0][0]=true;
    for(int i=1;i<=p.size();i++){
        if(p[i-1]=='*')dp[0][i] = dp[0][i-2];
    }
    for(int i=1;i<=s.size();i++){
        for(int j=1;j<=p.size();j++){
            if(p[j-1]=='*'){
                if(p[j-2]=='.'||p[j-2]==s[i-1]){
                    dp[i][j] = dp[i-1][j] || dp[i][j-1] || dp[i][j-2];
                }
                else{
                    dp[i][j] = dp[i][j-2];
                }
            }
            else{
                if(p[j-1]=='.'||p[j-1]==s[i-1]){
                    dp[i][j] = dp[i-1][j-1];
                }
            }
        }
    }
    cout<<(dp[s.size()][p.size()]?"true":"false");
    return 0;
}

上一题