10. Regular Expression Matching
题目描述
Given an input string (s) and a pattern §, implement regular expression matching with support for ‘.’ and '’.
给出一个字符串s和一个正则模式p,实现一个支持’.’,’'的正则表达式匹配函数
‘.’ Matches any single character. 匹配任意一个字符
‘*’ Matches zero or more of the preceding element. 表示前字符出现任意次数
注意:
s 可以为空,并且只包含a-z
p 可以为空,并且只包含a-z,’.’,’*’
思路
首先,直接匹配字符或者通配符的匹配都比较简单,关键是这个代表的任意个匹配前一字符比较麻烦。
我们可以维持两个指针i,j,标识两个字符串的匹配进度,如果两者同时到达了字符串终点,那么就可以认为是匹配成功结束。如果其中一方有剩余,或者中途已经无法匹配,那就是匹配失败。
遇到的时候我们就使用递归调用,从匹配零个,匹配一个,匹配n个,直到无法匹配(即没有相同的前个字符了)
代码
/**
* @param {string} s
* @param {string} p
* @return {boolean}
*/
var isMatch = function (s, p) {
// 两个字符串s,p,两个长度slen,plen等于是存在外函数里面,等下的所有递归调用的内函数都可以访问。如果写成c的话就要传进去了
var str = 0, ptr = 0;
var slen = s.length, plen = p.length;
// 实际上的递归函数
function Match(str, ptr) {
//console.log("s: "+str+" ; p: "+ptr);
if (str > slen) return false;
if (ptr > plen) return false;
// 终止条件
// 两者都结束,或者s结束p剩下的全是x*y*了
// 现在如果s已经结束,那么我就判断p是否结束或者剩下的全是x*的格式
if (str == slen) {
var gap = true;
// 用一个boolen变量控制一次字符、一次*
while (ptr != plen) {
if (gap && p[ptr] != '*' || !gap && p[ptr] == '*') {
ptr++;
} else {
break;
}
gap = !gap;
}
if (ptr == plen && gap) {
return true;
}
}
// 递归求值
else {
// 如果p的下一个值不是'*',那么直接比较当前值
if (p[ptr+1] != '*') {
if (s[str] == p[ptr] || p[ptr] == '.') {
return Match(str+1, ptr+1);
} else {
return false;
};
// 下一个值是*就要把ptr,ptr+1一同考虑,然后让他们匹配0到n个字符
} else {
// 但是还是有一个比较奇特的地方就是'.',因为他可以匹配任意字符,".*"的话就比较神奇了
var result = Match(str, ptr + 2);
while (str < slen && p[ptr] == '.' || s[str] == p[ptr]) {
result = result || Match(str + 1, ptr + 2);
str++;
}
return result || Match(str, ptr + 2);
}
}
return false;
}
// 直接返回函数递归调用的结果好像会出错,弄一个变量先保存在返回好了
var result = Match(str, ptr);
return result;
}