Leetcode 10. 正規表示式匹配

Geek0070發表於2024-10-07

1.題目基本資訊

1.1.題目描述

給你一個字串 s 和一個字元規律 p,請你來實現一個支援 ‘.’ 和 ‘*’ 的正規表示式匹配。

  • ‘.’ 匹配任意單個字元
  • ‘*’ 匹配零個或多個前面的那一個元素

所謂匹配,是要涵蓋 整個 字串 s 的,而不是部分字串。

1.2.題目地址

https://leetcode.cn/problems/regular-expression-matching/description/

2.解題方法

2.1.解題思路

動態規劃

2.2.解題步驟

在這裡插入圖片描述

第一步,狀態定義;dp[i][j]為s的前i個字串和p的前j個字串是否匹配

第二步,狀態初始化。初始化當匹配字串為空時的匹配狀態(即j=0時的狀態),因為除了原字串為空時,dp[0][0]=True,其餘的情況下dp[x][0]=False,所以只需要初始化dp[0][0]=True即可

第三步,狀態轉移。當判斷前i個字元和前j個匹配字元是否匹配時,這裡先預先定義倆字元匹配為匹配字元為.或者匹配字元和原字元兩者相等。

  • 如果最後一個匹配字元為號,並且倒數第二個匹配字元和原字串最後一個字元匹配,可以選擇讓匹配一次,去除當前s子串中匹配的部分,此時的狀態轉移為dp[i][j]=dp[i-1][j],當選擇讓*匹配0個,則去除匹配子串中的x*組合,此時狀態轉移為dp[i][j]=dp[i][j-2];
  • 如果最後一個匹配字元為*,並且倒數第二個匹配字元和原字串最後一個字元不匹配,則只能選擇讓*匹配0次,此時dp[i][j]=dp[i][j-2];
  • 如果最後一個匹配字元不為*號,並且該匹配字元與原字串中最後一個字元匹配,此時的轉移方程為dp[i][j]=dp[i-1][j-1];
  • 如果最後一個匹配字元不為*號,並且該匹配字元與原字串最後一個字元不匹配,則當前的原字串和匹配字串一定無法匹配,即dp[i][j]=False。

經過遍歷,最終的dp[sLen][pLen]即為題解

3.解題程式碼

Python程式碼

class Solution:
    def isMatch(self, s: str, p: str) -> bool:
        sLen,pLen=len(s),len(p)
        # 第一步,狀態定義;dp[i][j]為s的前i個字串和p的前j個字串是否匹配
        dp=[[False]*(pLen+1) for i in range(sLen+1)]
        # 第二步,狀態初始化。初始化當匹配字串為空時的匹配狀態(即j=0時的狀態),因為除了原字串為空時,dp[0][0]=True,其餘的情況下dp[x][0]=False,所以只需要初始化dp[0][0]=True即可
        dp[0][0]=True   # 兩個都是空字串時,匹配
        # 第三步,狀態轉移。當判斷前i個字元和前j個匹配字元是否匹配時,這裡先預先定義倆字元匹配為匹配字元為.或者匹配字元和原字元兩者相等。如果最後一個匹配字元為*號,並且倒數第二個匹配字元和原字串最後一個字元匹配,可以選擇讓*匹配一次,去除當前s子串中匹配的部分,此時的狀態轉移為dp[i][j]=dp[i-1][j],當選擇讓*匹配0個,則去除匹配子串中的x*組合,此時狀態轉移為dp[i][j]=dp[i][j-2];如果最後一個匹配字元為*,並且倒數第二個匹配字元和原字串最後一個字元不匹配,則只能選擇讓*匹配0次,此時dp[i][j]=dp[i][j-2];如果最後一個匹配字元不為*號,並且該匹配字元與原字串中最後一個字元匹配,此時的轉移方程為dp[i][j]=dp[i-1][j-1];如果最後一個匹配字元不為*號,並且該匹配字元與原字串最後一個字元不匹配,則當前的原字串和匹配字串一定無法匹配,即dp[i][j]=False。經過遍歷,最終的dp[sLen][pLen]即為題解
        # > 判斷s[i]字元和p的p[j]字元是否匹配
        def match(i,j):
            if i<0 or j<0:
                return False
            if p[j]==".":
                return True
            elif p[j]==s[i]:
                return True
            else:
                return False
        for i in range(sLen+1):
            for j in range(1,pLen+1):
                if p[j-1]!="*":
                    if match(i-1,j-1):
                        dp[i][j]=dp[i-1][j-1]
                    else:
                        dp[i][j]=False
                else:
                    if match(i-1,j-2):
                        dp[i][j]=dp[i-1][j] or dp[i][j-2]
                    else:
                        dp[i][j]=dp[i][j-2]
        # print(dp[sLen][pLen])
        return dp[sLen][pLen]

C++程式碼

class Solution {
public:
    bool match(int i,int j,string s,string p){
        if(i<0 || j<0){
            return false;
        }
        if(p[j]=='.'){
            return true;
        }else if(p[j]==s[i]){
            return true;
        }else{
            return false;
        }
    }
    bool isMatch(string s, string p) {
        int sLen=s.size(),pLen=p.size();
        vector<vector<bool>> dp(sLen+1,vector<bool>(pLen+1,false));
        dp[0][0]=true;
        for(int i=0;i<sLen+1;++i){
            for(int j=1;j<pLen+1;++j){
                if(p[j-1]!='*'){
                    if(match(i-1,j-1,s,p)){
                        dp[i][j]=dp[i-1][j-1];
                    }else{
                        dp[i][j]=false;
                    }
                }else{
                    if(match(i-1,j-2,s,p)){
                        dp[i][j]=dp[i-1][j] || dp[i][j-2];
                    }else{
                        dp[i][j]=dp[i][j-2];
                    }
                }
            }
        }
        return dp[sLen][pLen];
    }
};

4.執行結果

在這裡插入圖片描述

相關文章