本文已参与「新人创作礼」活动,一起开启掘金创作之路。
题目
给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配。
'.'匹配任意单个字符'.'匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。
输入: s = "aa", p = "a"
输出: false
解释: "a" 无法匹配 "aa" 整个字符串。
解题思路
思路一
.和*符合常规正则匹配,因为是对整个字符串进行校验,所以首要加^开始,尾要$终止, 如果题目还有其他不常规的匹配条件,可以先把p替换成常规的条件即可。
var isMatch = function (s, p) {
return new RegExp(['^', p, '$'].join('')).test(s);
};
思路二
我们这里还可以使用递归方式实现
let isMatch = (s,p)=>{
//边界问题如果s和p都为空,满足
if(p.length<=0){
return !s.length
}
let match = false
//判断第一个字符是否匹配,首先保证s不能为空,否则无法匹配,然后开始比较s和p的第一个字符,如果p[0]是‘.’,代表匹配所有字符,也满足
if(s.length>0&&(p[0]===s[0]||p[0]==='.')){
match = true
}
//p带模式
if(p.length>1&&p[1]==='*'){
//两种情况
//第一种p*为0
//第二种p*为多个
return isMatch(s,p.slice(2)) || (match&&isMatch(s.slice(1),p))
}else {
return match&&isMatch(s.slice(1),p.slice(1))
}
};
思路三
我们先根据规则p生成匹配图表,然后再根据图表去消耗待匹配的字符串,在遇到
*时,查找出可匹配的字符有几个,并从0到count开始递归消耗字符串,若全部返回false则为false,若有一个为true则视为次规则可以匹配此字符串
const toMatchArr = function(p){
const matchArr = [];
p.forEach((item) =>{
if (item==='*') {
matchArr[matchArr.length-1] += '-*';
}else{
matchArr.push(item)
}
})
return matchArr;
}
const findCount = function(s,tar){
if(tar==='.') return s.length;
let count = 0;
while(tar === s[count]){
count++;
}
return count;
};
const subStrWithMatch = function(s, matchArr){
while(matchArr.length){
const match = matchArr.shift();
if (match.length===1){
const sub = s.shift();
if (sub && (match[0]===sub || match[0]==='.')){
return subStrWithMatch(s, matchArr);
}else{
return false;
}
}else{
const count = findCount(s, match[0]);
if(count===0) continue;
let i = 0;
while(count>=i){
if (i) s.shift();
if (subStrWithMatch([...s], [...matchArr])){
return true;
}
i++;
continue;
}
return false;
}
}
if (s.length) return false;
return true;
}
const isMatch = function(s, p) {
p = p.split('');
s = s.split('');
return subStrWithMatch(s, toMatchArr(p));
};