剑指offer(52)正则表达式的匹配
题目描述
请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配
题目分析
说实话这道题有点像编译原理中的状态机,我们做的时候可以结合 画图 来做。
第一种方法是我们比较容易想到的就是用js的原生方法,这个比较简单,不过这题显然是考我们如何去实现原生的方法,也就是第二种方法。
第二种方法说实话还是比较难的,因为情况比较复杂,需要理清思路。不过首先我们想到的是这题肯定需要用递归,也就是关键就是如何写这个递归函数,以及需要哪些参数!
理清思路:
当模式中的第二个字符不是“*”时
1.如果字符串中的第一个字符和模式中的第一个字符相匹配,那么在字符串和模式上都向后移动一个字符,然后匹配剩余的字符串和模式。
2.如果字符串中的第一个字符和模式中的第一个字符不相匹配,则直接返回false。
当模式中第二个字符是“*”时,有多种不同匹配方式。
1.在模式上上向后移动两个字符,相当于x*被忽略。因为“*”可以匹配字符串中的0个字符。
2.如果模式中第一个字符和字符串中的第一个字符相匹配,则在字符串上向后移动一个字符。
这种情况下可以有两种选择:
a.模式上向后移动两个字符
b.模式保持不变
对于JS语言来说,我们的递归函数除了字符串和模式外,还需要两个额外参数来记录下当前在字符串和模式上移动的位置索引。
代码
第一种方法:
// 第一种 function match(s, pattern) { const reg = new RegExp(`^${pattern}$`); return reg.test(s); }
第二种方法:
// 第二种 function matchCore(s, istr, pattern, ipattern) { if (istr === s.length && ipattern === pattern.length) { return true; } if (istr !== s.length && ipattern === pattern.length) { return false; } if (pattern[ipattern + 1] === '*') { if (pattern[ipattern] === '.' && istr !== s.length || pattern[ipattern] === s[istr]) { return ( matchCore(s, istr + 1, pattern, ipattern + 2) || matchCore(s, istr + 1, pattern, ipattern) || matchCore(s, istr, pattern, ipattern + 2) ); } return matchCore(s, istr, pattern, ipattern + 2); } if (s[istr] === pattern[ipattern] || pattern[ipattern] === '.' && istr !== s.length) { return matchCore(s, istr + 1, pattern, ipattern + 1); } return false; } function match2(s, pattern) { if (s === null || pattern === null) { return false; } return matchCore(s, 0, pattern, 0); }