题目描述
LeetCode 10
给定一个字符串 (s
) 和一个字符模式 (p
)。实现支持 '.'
和 '*'
的正则表达式匹配。
'.' 匹配任意单个字符。 '*' 匹配零个或多个前面的元素。
匹配应该覆盖整个字符串 (s
) ,而不是部分字符串。
说明:
s
可能为空,且只包含从a-z
的小写字母。p
可能为空,且只包含从a-z
的小写字母,以及字符.
和*
。
示例 1:
输入: s = "aa" p = "a" 输出: false 解释: "a" 无法匹配 "aa" 整个字符串。
示例 2:
输入: s = "aa" p = "a*" 输出: true 解释: '*' 代表可匹配零个或多个前面的元素, 即可以匹配 'a' 。因此, 重复 'a' 一次, 字符串可变为 "aa"。
示例 3:
输入: s = "ab" p = ".*" 输出: true 解释: ".*" 表示可匹配零个或多个('*')任意字符('.')。
示例 4:
输入: s = "aab" p = "c*a*b" 输出: true 解释: 'c' 可以不被重复, 'a' 可以被重复一次。因此可以匹配字符串 "aab"。
示例 5:
输入: s = "mississippi" p = "mis*is*p*." 输出: false
《剑指offer》
请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配
解题思路
下文综合整理自牛客网,加入了自己的总结与补充。
【1】当模式中的第二个字符是“*”时:
1、如果字符串第一个字符跟模式第一个字符不匹配,则模式后移2个字符,继续匹配。
如:
字符串 abc ————> abc
模式串 b*a ————> b*a
结论:当前位不相同,一个为a,一个为b,模式串后移2位,继续比较............
2、如果字符串第一个字符跟模式第一个字符匹配(相同或者模式为'.'),可以有3种匹配方式:
(1)模式后移2字符,相当于x*被忽略;
如:
字符串 abc ————> abc
模式串 .*ac ————> .*a
结论:该方式主要用来应对模式'.'匹配a的情况,可以看到,模式串后移2位,可以方便地继续比较............
(2)字符串后移1字符,模式后移2字符;
如:
字符串 abc ————> abc
模式串 a*bc ————> a*bc
结论:该方式主要用来应对一个a匹配a*的情况,字符串后移1位,模式串后移2位,愉快地继续比较............
(3)字符串后移1字符,模式不变,即继续匹配字符下一位,因为*可以匹配多位;
如:
字符串 aaaaaaabc ————> aaaaaaabc
模式串 a*bc ————> a*bc
结论:该方式主要用来应对一串a匹配a*的情况,字符串后移1位,模式串不变,开心地继续比较............
【2】当模式中的第二个字符不是“*”时:
1、如果字符串第一个字符和模式中的第一个字符相匹配,那么字符串和模式都后移一个字符,然后匹配剩余的。
如:
字符串 abd
模式串 acd
结论:当前位相同,都为a,匹配下一个
2、如果字符串第一个字符和模式中的第一个字符相不匹配,直接返回false。如:
字符串 abd
模式串 acd
结论:当前位不相同,一个为b,一个为c,返回false
代码实现
public class Solution {
public boolean match(char[] str, char[] pattern)
{
//如果输入为空,返回匹配失败
if(str == null || pattern == null) return false;
return match(str, pattern, 0, 0);
}
private boolean match(char[] str, char[] pattern, int strIndex, int patIndex) {
//如果字符串和模式同时遍历完成,说明匹配成功
if(strIndex == str.length && patIndex == pattern.length)
return true;
//如果字符串还没有遍历完,模式已经遍历完,说明匹配失败
if(strIndex != str.length && patIndex == pattern.length)
return false;
//【1】当模式中的第二个字符是“*”时:
if(patIndex < pattern.length - 1 && pattern[patIndex + 1] == '*') {
//2、如果字符串第一个字符跟模式第一个字符匹配(相同或者模式为'.'),可以有3种匹配方式:
if(strIndex < str.length && (pattern[patIndex] == str[strIndex]
|| pattern[patIndex] == '.')) {
//(2)字符串后移1字符,模式后移2字符;
return match(str, pattern, strIndex + 1, patIndex + 2)
//(3)字符串后移1字符,模式不变,即继续匹配字符下一位,因为*可以匹配多位;
|| match(str, pattern, strIndex + 1, patIndex)
//(1)模式后移2字符,相当于x*被忽略;
|| match(str, pattern, strIndex, patIndex + 2);
} else {
//1、如果字符串第一个字符跟模式第一个字符不匹配,则模式后移2个字符,继续匹配。
return match(str, pattern, strIndex, patIndex + 2);
}
}
//【2】当模式中的第二个字符不是“*”时:tips!!!切记要把对下标的合法性检查放在&&左侧
if(strIndex < str.length && (pattern[patIndex] == str[strIndex]
|| pattern[patIndex] == '.')) {
//1、如果字符串第一个字符和模式中的第一个字符相匹配
return match(str, pattern, strIndex + 1, patIndex + 1);
}
//2、如果字符串第一个字符和模式中的第一个字符相不匹配,直接返回false
return false;
}
}
根据思路一步步进行代码实现,果然“磨刀不误砍柴工”~
更多算法解答请点击《剑指offer》66题JAVA代码算法实现全集