具体题目说明:https://www.lintcode.com/problem/regular-expression-matching/description
觉得这个比较有意思,就研究了下,算是温习了下DP,这是个普通实现,对一些关键步骤做了理解和说明
Java实现
/**
* 实现支持'.'和'*'的正则表达式匹配
* .匹配任意一个字母 *匹配零个或者多个前面的元素
* @param s 待匹配的字符串
* @param p 表达式
* @return 是否匹配
*/
public static boolean isMatch(String s, String p) {
int s_length = s.length();
int p_length = p.length();
// record表示s中的前i个字符与p中的前j个字符匹配情况
boolean[][] record = new boolean[s_length + 1][p_length + 1];
// 然后从s第一个字符开始匹配,都能匹配上那么就算成功
for (int i = 0; i <= s_length; i++) {
for (int j = 0; j <= p_length; j++) {
// 初始化,可以理解为""和""匹配
if (i == 0 && j == 0) {
record[i][j] = true;
continue;
}
// 表示任意除""外的字符和""表达式均不匹配
// 这里可能有一个疑问,为什么没有i == 0的情况,我们举个例子s为"",p为a*,他们就是匹配关系
if (j == 0) {
record[i][j] = false;
continue;
}
// 这里即用动态规划,从前后关系上来逐步推断匹配关系,从初始状态一步步计算后面每步结果
// 情况1: 当i处字符和j处字符相同或者j处字符为'.'时,i及之前的字符串和j及之前的字符串是否匹配
// 只取决于i-1和j-1处匹配状况
if (i > 0 && (s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '.')) {
record[i][j] = record[i - 1][j - 1];
} else if (p.charAt(j - 1) == '*' && j > 1) {
// 情况2: 当j处字符为'*'时(注意j>1),这里就分'*'匹配零个和多个,任意一个匹配上均表示匹配上
// 情况2-1: 当'*'之前一个(j-2)字符和i处字符相同或者'*'之前一个(j-2)字符为'.'时,
// 这时'*'至少匹配一个字符,那么消掉i处一个字符,所以i,j处的匹配关系由i-1,j即可确定
if (i > 0 && (s.charAt(i - 1) == p.charAt(j - 2) || p.charAt(j - 2) == '.')) {
record[i][j] = record[i - 1][j];
}
// 情况2-2: 匹配零个,注意使用|(或)的关系
// 理解""和a*匹配这个例子很重要,因为*匹配零个或者多个多个前面的元素,所以当j为*时,匹配零个'a',
// 故可消掉*和'a',那么只需看""和'a'之前的字符是否匹配即可,也就是j-2
record[i][j] |= record[i][j - 2];
}
}
}
return record[s_length][p_length];
}