10.Regular Expression Matching

问题描述:

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

思路:

本题要求我们进行正则匹配。

可匹配的符号有两个:

1. ‘*’ 0个或多个前一个字符(字符和‘.’)

2. ‘.’ 任意一个字母

在这里需要注意的是:

“.* ”可以匹配任意字符串因为其代表着0个或多个 '.' , 也就是说可以匹配空字符串以及任意字母组成的任意长度的字符串。

参考:http://www.cnblogs.com/grandyang/p/4461713.html

一开始我只想要要分情况,并且用指针来解决,但是由于‘*’可以代表零个或多个字符,所以对于怎样移动指针没有好的思路。

大佬的讲解给了我思路。

分情况:

1.匹配字符串p为空,此时需判断待匹配字符串s是否为空

2.匹配字符串p长度为1,需要判断s的长度以及s的内容,需要注意的是,若s长度为一,当p = ‘.’ 时也匹配成功

3.匹配字符串p长度不为1:

  1). p[1] != '*': 前一段字符串长度不可变,可直接比较s[0] == p[0],若相等,对s和p下标为1到结尾的子串进行匹配。

  2).p[2] != '*': 前一段字符长度可能变化, 当s不为空的时候

            a. 若s[0] == p[0]时,可以尝试p.substr(2)与s进行匹配(因为前两个字符为"x*")

            b. 若p[0] == '.'时,可匹配任意字母,所以也直接尝试p.substr(2)与s进行匹配。

  当s为空或者上述两种情况都不成立时,直接比较 s 与 p.substr(2)          

代码:

class Solution {
public:
    bool isMatch(string s, string p) {
        if(p.empty())
            return s.empty();
        if(p.size() == 1){
            return (s.size() == 1 && (p[0] == s[0] || p[0] == '.'));
        }
        if(p[1] != '*'){
            if(s.empty()) 
         return false; return (p[0] == s[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)); } };

动态规划:

居然可以用动态规划解啊朋友们!!

m为s长度,n为p长度

P[i][j] 代表 s的前i个字符能否跟p的前j个字符匹配。

所以有前0个字符。

P[0][0] = true;

对第一列P[i][0]进行初始化,i 从1 到m-1为false

对第一行P[0]进行初始化,从1开始,遇到‘*’时需要特殊讨论:

      if(p[i-1] == '*') dp[0][i] = dp[0][i-2]; 

状态转移方程:

1.  P[i][j] = P[i - 1][j - 1], if p[j - 1] != '*' && (s[i - 1] == p[j - 1] || p[j - 1] == '.');

2.  P[i][j] = P[i][j - 2], if p[j - 1] == '*' and the pattern repeats for 0 times;
3.  P[i][j] = P[i - 1][j] && (s[i - 1] == p[j - 2] || p[j - 2] == '.'), if p[j - 1] == '*' and the pattern repeats for at least 1 times.

时隔很久,回来填坑。

代码:

class Solution {
public:
    bool isMatch(string s, string p) {
        int m = s.size();
        int n = p.size();
        vector<vector<bool>> dp(m+1, vector<bool>(n+1, false));
        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(p[j-1] != '*'){
                    dp[i][j] = dp[i-1][j-1] && (s[i-1] == p[j-1] || p[j-1] == '.');
                }else{
                    dp[i][j] = dp[i][j-2] || ((s[i-1] == p[j-2] || p[j-2] == '.') && dp[i-1][j]);
                }
            }
        }
        return dp[m][n];
    }
};
原文地址:https://www.cnblogs.com/yaoyudadudu/p/9108851.html