10. Regular Expression Matching
题目链接:10. Regular Expression Matching
题意
实现正则表达式中对.和*的支持。点号匹配任意单个字符,星号匹配任意个它前面的字符,包括0个。
解法
可用动态规划求解,match[i][j]表示模式p从0到i-1的子串能否与字符串s从0到j-1的子串匹配。
状态转移:
- 当p[i-1]不是星号时,只需要满足s[j-1]能匹配p[i-1]就能转移到更小的子问题match[i-1][j-1];
- 当p[i-1]是星号时,考虑星号匹配0个字符和多个字符两种情况:
- 星号匹配0个字符说明s[0~j-1]必须与p[0~i-3]匹配
- 如果星号匹配多个字符,则在确保s[j-1]匹配p[i-1]后可以转移到更小的子问题match[i][j-1],注意这里i没有减小,因为星号可能继续匹配字符
所以动态规划数组表达式如下:
match[i][j]=⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪true,false,p[i−1]==′∗′且match[i−2][0],match[i−2][j]||(s[j−1]==p[i−2]||p[i−2]==′.′)且match[i][j−1],match[i][j]=match[i−1][j−1]且(p[i−1]==s[j−1]||p[i−1]==′.′),i==0并且j==0(空模式匹配空字符串)i==0并且j>0(空模式不匹配非空字符串)j==0并且i>0p[i−1]==′∗′p[i−1]!=′∗′
返回match[m][n],m、n分别是模式和字符串的长度。
代码
#include<iostream>
#include<string>
#include<vector>
using namespace std;
class Solution {
public:
bool isMatch(string s, string p) {
int m = p.length(), n = s.length();
if (!m)
return !n;
bool **match = new bool*[m + 1];
for (int i = 0; i < m + 1; ++i) {
match[i] = new bool[n + 1];
memset(match[i], 0, sizeof(bool)*(n + 1));
}
match[0][0] = true;//empty expression matches empty string
for (int i = 1; i < m + 1; ++i) {
match[i][0] = p[i - 1] == '*' && match[i - 2][0];
}
for (int i = 1; i < m + 1; ++i) {
for (int j = 1; j < n + 1; ++j) {
if (p[i - 1] == '*') {
match[i][j] = match[i - 2][j] //x* matches nothing
|| (s[j - 1] == p[i - 2] || p[i - 2] == '.') && match[i][j - 1];//x matches s[j-1] and s[0~j-2] matches p[0~i-1]
}
else {
match[i][j] = match[i - 1][j - 1] && (p[i - 1] == s[j - 1] || p[i - 1] == '.');
}
}
}
return match[m][n];
}
};
算法复杂度
算法复杂度为O(n*m)。