1. 程式人生 > >LeetCode 10 & 44 正則表示式匹配 & 萬用字元匹配 字串匹配問題

LeetCode 10 & 44 正則表示式匹配 & 萬用字元匹配 字串匹配問題

10 正則表示式匹配
給定一個字串 (s) 和一個字元模式 (p)。實現支援 ‘.’ 和 ‘*’ 的正則表示式匹配。

‘.’ 匹配任意單個字元。
‘*’ 匹配零個或多個前面的元素。
匹配應該覆蓋整個字串 (s) ,而不是部分字串。

說明:

s 可能為空,且只包含從 a-z 的小寫字母。
p 可能為空,且只包含從 a-z 的小寫字母,以及字元 . 和 *。
示例 1:

輸入:
s = “aa”
p = “a”
輸出: false
解釋: “a” 無法匹配 “aa” 整個字串。
示例 2:

輸入:
s = “aa”
p = “a*”
輸出: true
解釋: ‘*’ 代表可匹配零個或多個前面的元素, 即可以匹配 ‘a’ 。因此, 重複 ‘a’ 一次, 字串可變為 “aa”。
示例 3:

輸入:
s = “ab”
p = “.*”
輸出: true
解釋: “.” 表示可匹配零個或多個(‘‘)任意字元(‘.’)。
示例 4:

輸入:
s = “aab”
p = “c*a*b”
輸出: true
解釋: ‘c’ 可以不被重複, ‘a’ 可以被重複一次。因此可以匹配字串 “aab”。
示例 5:

輸入:
s = “mississippi”
p = “mis*is*p*.”
輸出: false

分析:用dp[i][j]表示匹配串的前i位與模式串的前j位是否匹配
*的處理:星號有兩種情況:星號前邊的字元1.出現0次 2.出現1次或多次
如果出現0次,那麼模式串中第j位和第j-1位都沒有作用 dp[i][j] = dp[i][j-2]
如果出現1至多次,
繼續考慮,如果只出現1次,既有可能唯一的1次出現在匹配串的i-1位,這個時候第i-1位與第j位必然匹配; 也有可能 匹配串的i-1位與模式串的j-2位匹配,唯一的1次出現在第i位,此時匹配串的i-1位與模式串的j-1位也必然匹配,因為這個時候是將星號按0次出現處理。因此這兩種情況都必然有dp[i-1][j]為true
如果出現多次,那麼顯然有dp[i-1][j]為true,因為此時模式串的第i-1位一定和匹配串的第j-1位匹配
因此出現1至多次的情況必然滿足:
dp[i-1][j] 為true 且 匹配串的第i位與模式串的第j-1位匹配
細節:預處理時注意,dp[][0]一定為false ,因為模式串為空時它不可能與非空字串匹配
而dp[0][]不一定為false,因為一個空串是有可能與類似於A*之類的模式串匹配的

class Solution {
public:
    bool isMatch(string s, string p) {
        int s_len = s.size();
        int p_len = p.size();
        vector<vector<int>> dp(s_len+1,vector<int>(p_len+1,0));
        dp[0][0] =1;

        for(int j = 2 ; j <= p_len ; j ++ )
        {
            dp[0][j]= (p[j-1
] == '*' && dp[0][j-2]); } for(int i = 1 ; i <= s_len ; i ++ ) { for(int j = 1 ; j <= p_len ; j ++ ) { if(p[j-1] == '*') { dp[i][j] = dp[i][j-2] ||(dp[i-1][j] && (s[i-1] == p[j-2] || p[j-2] =='.')); }else{ dp[i][j] = dp[i-1][j-1] && (s[i-1] == p[j-1] || p[j-1] == '.'); } } } return dp[s_len][p_len]; } };

另外在正則表示式中還有+:指前一位出現至少一次,這種情況就是*號的處理去掉空的情況。

44.萬用字元匹配
給定一個字串 (s) 和一個字元模式 (p) ,實現一個支援 ‘?’ 和 ‘*’ 的萬用字元匹配。

‘?’ 可以匹配任何單個字元。
‘*’ 可以匹配任意字串(包括空字串)。
兩個字串完全匹配才算匹配成功。

說明:

s 可能為空,且只包含從 a-z 的小寫字母。
p 可能為空,且只包含從 a-z 的小寫字母,以及字元 ? 和 *。
示例 1:

輸入:
s = “aa”
p = “a”
輸出: false
解釋: “a” 無法匹配 “aa” 整個字串。
示例 2:

輸入:
s = “aa”
p = “*”
輸出: true
解釋: ‘*’ 可以匹配任意字串。
示例 3:

輸入:
s = “cb”
p = “?a”
輸出: false
解釋: ‘?’ 可以匹配 ‘c’, 但第二個 ‘a’ 無法匹配 ‘b’。
示例 4:

輸入:
s = “adceb”
p = “*a*b”
輸出: true
解釋: 第一個 ‘’ 可以匹配空字串, 第二個 ‘’ 可以匹配字串 “dce”.
示例 5:

輸入:
s = “acdcb”
p = “a*c?b”
輸入: false

分析:
*的處理:
星號可以匹配任意字串,考慮當模式串第j位為星號時,字串第i位如果想要和它匹配有哪些情況?
1.*代表空串 第i位必須與星號前一位匹配
2.*不是空串 第i位位於星號代表的字串的首位 這個時候第i-1位必須與星號前一位匹配 同時 也必須與星號匹配 (對第i-1位星號代表空串)
3.*不是空串 第i位位於星號代表的字串的非首位 這個時候第i-1位一定也在星號代表的字串內 也必須與星號匹配
所以匹配時一定滿足:dp[i][j-1] == true || dp[i-1][j] == true

class Solution {
public:
    bool isMatch(string s, string p) {
        int sl = s.length();
        int pl = p.length();
        vector<vector<int>> dp;
        dp.resize(sl+1,vector<int>(pl+1,0));
        dp[0][0] = 1;
        for(int j = 1 ; j <= pl ; j ++ )
        {
            if(p[j-1] == '*') dp[0][j] = dp[0][j-1];
        }
        for(int i = 1 ; i <= sl ; i ++ )
        {
            for(int j = 1 ; j <= pl ; j ++ )
            {
                if(p[j-1] == '*')
                {
                    if(dp[i][j-1] || dp[i-1][j])
                    {

                    dp[i][j] =1;
                    }
                }else if(p[j-1] == '?')
                {
                    dp[i][j] = dp[i-1][j-1];
                }else{
                    if(s[i-1] == p[j-1])
                    {
                        dp[i][j] = dp[i-1][j-1];
                    }
                }
            }
        }
        return dp[sl][pl];
    }
};