• 10. Regular Expression Matching


    问题:

    给定一个字符串s,和一个模式串p,求p是否能匹配s

    正则表达支持以下两种符号

    '.' Matches any single character.
    '*' Matches zero or more of the preceding element.
    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 preceding 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(动态规划)

    1.确定【状态】:

    • 字符串s的第i个字符:s[i]
    • 匹配串第j个字符:p[j]

    2.确定【选择】:dp[i][j] 分3种情况

    • s[i] == p[j] 或者 p[j] == '.' :该字符匹配
      • 前一个子串状态:  =dp[i-1][j-1]
    • p[j] == '*':该字符可能匹配上"#*" (#为某一字符p[j-1]),分以下2种情况
      • p[j-1]这个字符不匹配当前s[i],即p[j-1]!=s[i] && p[j-1]!='.'
        • 则要使该字符匹配,"#*"必定与字符串s匹配0次(匹配串的 j 跳过两个字符#*):=dp[i][j-2]
      • p[j-1]这个字符匹配当前s[i],则又分为以下三种"#*"的匹配情况,他们之间求OR:
        • 匹配0次(匹配串的 j 跳过两个字符#*,字符串的 i 跳过0个字符):=dp[i][j-2]
        • 匹配1次(匹配串的 j 跳过两个字符#*,字符串的 i 跳过一个字符):=dp[i-1][j-2]
        • 匹配>1次(匹配串的 j 跳过0个字符,字符串的 i 跳过一个字符):=dp[i-1][j]
    • 该字符未匹配
      • false

    3. dp[i][j]的含义:

    字符串s的0~第 i 个字符,是否能被匹配串p的0~第 j 个字符,匹配上。

    4. 状态转移:

    dp[i][j]=

    • (s[i] == p[j] 或者 p[j] == '.' ):=前一个子串状态:dp[i-1][j-1]
    • (p[j] == '*'):
      • 前一个字符#不匹配s当前字符(p[j-1]!=s[i] && p[j-1]!='.')
        • 则使#*匹配0次:dp[i][j-2]
      • 前一个字符#匹配s当前字符,OR {
        • 使#*匹配0次:dp[i][j-2]
        • 使#*匹配1次:dp[i-1][j-2]
        • 使#*匹配>1次:dp[i-1][j] }
    • 其他则不匹配:=false

    5. base case:

    • dp[i][0]=false:任意字符串s,匹配空串,除非空串自己,其他都为false。
      • dp[0][0]=true
    • dp[0][2j]=true:当dp[0][2j-1]==true && p[2j]=='*'
      • "#*#*#*...#*"只有这种情况能匹配任意空串字符串s。

    代码参考:

     1 class Solution {
     2 public:
     3     //dp[i][j]:s[0~i],p[0~j] are matched?
     4     //case_1:s[i]==p[j] or p[j]=='.': dp[i-1][j-1]
     5     //case_2:p[j]=='*':
     6     //       case_2_1, s[i]!=p[j-1]->match 0 time: dp[i][j-2]
     7     //               #####a(i)
     8     //                    ^
     9     //               ####b*(j)
    10     //                  ^
    11     //       case_2_2, s[i]==p[j-1] or p[j]=='.' ->
    12     //               #####a(i)   or   #####a(i)
    13     //               ####.*(j)        ####a*(j)
    14     //                 match 0 time: dp[i][j-2]
    15     //              or match 1 time: dp[i-1][j-2]
    16     //               #####a(i)
    17     //                   ^
    18     //               ####a*(j)
    19     //                  ^
    20     //              or match >1 times: dp[i-1][j]
    21     //               #####a(i)
    22     //                   ^
    23     //               ####a*(j)
    24     //                    ^
    25     //base case:
    26     //dp[i][0]=false
    27     //dp[0][j]=p[j]=='*'&&dp[0][j-2]->"#*#*#*..."
    28     //dp[0][0]=true
    29     bool isMatch(string s, string p) {
    30         int n=s.length(), m=p.length();
    31         vector<vector<bool>> dp(n+1, vector<bool>(m+1, false));
    32         dp[0][0]=true;
    33         for(int j=2; j<=m; j+=2) {
    34             if(p[j-1]=='*' && dp[0][j-2]) {
    35                 dp[0][j] = true;
    36             }
    37         }
    38         for(int i=1; i<=n; i++) {
    39             for(int j=1; j<=m; j++) {
    40                 if(s[i-1] == p[j-1] || p[j-1] == '.') {
    41                     dp[i][j] = dp[i-1][j-1];
    42                 } else if(p[j-1] == '*') {
    43                     if(s[i-1] != p[j-2] && p[j-2] != '.') {
    44                         dp[i][j] = dp[i][j-2];
    45                     } else {
    46                         dp[i][j] = dp[i][j-2] || dp[i-1][j-2] || dp[i-1][j];
    47                     }
    48                 }
    49             }
    50         }
    51         return dp[n][m];
    52     }
    53 };
  • 相关阅读:
    2020年12月2日
    2020年12月1日
    2020年11月30日
    2020年11月29日
    2020年11月28日
    2020年11月27日
    2020年11月26日
    2020年11月25日
    浅谈扩展欧几里得算法
    Hello 2020
  • 原文地址:https://www.cnblogs.com/habibah-chang/p/13647616.html
Copyright © 2020-2023  润新知