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 lettersa-z
.p
could be empty and contains only lowercase lettersa-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]; } };