Given an input string (s
) and a pattern (p
), implement regular expression matching with support for '.'
and '*'
.
'.' Matches any single character. '*' Matches zero or more of the preceding element.
The matching should cover the entire input string (not partial).
Note:
s
could be empty and contains only lowercase lettersa-z
.p
could be empty and contains only lowercase lettersa-z
, and characters like.
or*
.
Example 1:
Input: s = "aa" p = "a" Output: false Explanation: "a" does not match the entire string "aa".
Example 2:
Input: s = "aa" p = "a*" Output: true Explanation: '*' means zero or more of the precedeng element, 'a'. Therefore, by repeating 'a' once, it becomes "aa".
Example 3:
Input: s = "ab" p = ".*" Output: true Explanation: ".*" means "zero or more (*) of any character (.)".
Example 4:
Input: s = "aab" p = "c*a*b" Output: true Explanation: c can be repeated 0 times, a can be repeated 1 time. Therefore it matches "aab".
Example 5:
Input:
s = "mississippi"
p = "mis*is*p*."
Output: false
一直在用正则表达式,那么是否有考虑过正则表达式是匹配是怎么实现的呢?现在这题就是正则的部分规则体现,试试能不能自己写一个正则表达式。
题目:给你两个字符串s 和 p,实现正则表达式的 "."和"*"的匹配规则
注:"."表示匹配任意字符,"*"表示匹配*前面那字符出现任意次数。
我靠,这还不简单?噼里啪啦,三两行代码完事。
public static boolean isMatch(String s, String p) {
java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(p);
return pattern.matcher(s).matches();
}
皮这一下就很开心,但是开心之后呢?人家是怎么实现的呢?
先提供一些测试数据
private static String[][] ss = {
{"aaa", "a*a"},{"ab", ".*c"},{"", "bab"}, {"aa", "a*"}, {"ab", ".*.."},
{"aaa", "aaaa"}, {"", ".*"}, {"aab", "cab"}, {"aaaa", "aaa"}, {"aab", "c*a*b"},
{"", "a*a*"}
};
private static boolean[] result = {true, false, false, true, true,
false, true, false, false, true, true,
true};
public static void main(String[] args){
if (false){
System.out.print(isMatch(ss[10][0], ss[10][1]));
}else {
for (int i = 0; i < ss.length; i++) {
try {
if (isMatch(ss[i][0], ss[i][1]) ^ result[i]){
System.out.println("索引为" + i + "的数据出错");
return;
}
}catch (Exception e){
System.out.println("索引为" + i + "的数据出现异常");
return;
}
}
System.out.print("结束,全部校验通过");
}
}
说来惭愧,写的过程不断调试,增加判断,过程中还换了一个思路去写,还是参考了LeetCode中的解决方案,最终才写完了下面的代码通过了测试。
最后的结果也是很惭愧的。
再来一个对比比较鲜明的,系统的正则表达式通过测试的速度。
速度看上去是差不多的,但是架不住人家的功能强大啊,而我这个仅仅就支持了"." "*"这样一对比就根本没可比性了。好了,废话少说,先分享一下解题思路吧,老规矩,先上代码。
public static boolean isMatch(String s, String p) {
if (s.isEmpty()) return p.isEmpty() || (p.length() >= 2 && p.charAt(1) == '*' && isMatch(s, p.substring(2)));
if (p.length() > 1 && p.charAt(1) == '*'){
if (p.charAt(0) == s.charAt(0) || p.charAt(0) == '.'){
return isMatch(s.substring(1), p) || isMatch(s, p.substring(2));
}else {
return isMatch(s, p.substring(2));
}
}else {
if (!p.isEmpty() && (p.charAt(0) == s.charAt(0) || p.charAt(0) == '.')){
return isMatch(s.substring(1), p.substring(1));
}else {
return false;
}
}
}
抓住一个核心思想,就是目标值S和匹配规则P完全匹配上了,就返回True,否则在这个过程中出现了不匹配,那么就表示没有匹配上。
下面聊聊写这个方法的心路历程吧,分享一下思考问题的方式,多是一些废话,各路大神没有兴趣就不用往下看了。
根据这个思路,出现了下面的代码,然后利用测试数据 "aaa", "a*a"进行测试时发现并不能匹配上。
public static boolean isMatch(String s, String p) {
if (s.isEmpty()) return p.isEmpty();
if (p.length() > 1 && p.charAt(1) == '*'){
if (p.charAt(0) == s.charAt(0) || p.charAt(0) == '.'){
return isMatch(s.substring(1), p);
}else {
return isMatch(s, p.substring(2));
}
}else {
if (!p.isEmpty() && (p.charAt(0) == s.charAt(0) || p.charAt(0) == '.')){
return isMatch(s.substring(1), p.substring(1));
}else {
return false;
}
}
}
于是一顿跟踪调试,发现如果只是这样匹配,匹配规则P是无法匹配完全的,于是将代码继续进化
public static boolean isMatch(String s, String p) {
if (s.isEmpty()) return p.isEmpty();
if (p.length() > 1 && p.charAt(1) == '*'){
if (p.charAt(0) == s.charAt(0) || p.charAt(0) == '.'){
return isMatch(s.substring(1), p) || isMatch(s, p.substring(2));
}else {
return isMatch(s, p.substring(2));
}
}else {
if (!p.isEmpty() && (p.charAt(0) == s.charAt(0) || p.charAt(0) == '.')){
return isMatch(s.substring(1), p.substring(1));
}else {
return false;
}
}
}
如果前两个匹配是 x*的时候无法将s匹配完,那么就用下一组继续匹配,如果不是x*的模式,那么就表示s和p不匹配。然后继续测试,{"", "bab"}就遇到了这两个数。又是一顿调试,进化代码
public static boolean isMatch(String s, String p) {
if (s.isEmpty()) return p.isEmpty() || p.length() == 2 && p.charAt(1) == '*';
if (p.length() > 1 && p.charAt(1) == '*'){
if (p.charAt(0) == s.charAt(0) || p.charAt(0) == '.'){
return isMatch(s.substring(1), p) || isMatch(s, p.substring(2));
}else {
return isMatch(s, p.substring(2));
}
}else {
if (!p.isEmpty() && (p.charAt(0) == s.charAt(0) || p.charAt(0) == '.')){
return isMatch(s.substring(1), p.substring(1));
}else {
return false;
}
}
}
当s已经匹配完全了,如果p的最后一个字符是*那么就表示能够匹配上。继续调试遇到了{"aab", "c*a*b"}这俩兄弟,继续递归优化代码,首先发现了p.length()他不一定就只有一组x*的字符啊,所以将p.length() == 2 && p.charAt(1) == '*' 改为 p.length() >= 2 && p.charAt(1) == '*',接着测试{"ab", ".*c"}这哥俩又来了,于是出现了上面那段代码。