题目描述
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,在本题中"."代表任意字符,"*代表它前面的字符可以出现一次或者多次"
具体解法
先说一下我对这种题的理解:主要就是尽可能考虑多一些的情况,这样才能设计出覆盖率大的算法,首先我们要判断正则字符串p是是否为空,如果不是null,则判断长度是不是1,如果是1,判断字符串s长度是否也是1,并且能否与正则匹配,如果正则的长度不是1,判断p[1]是不是*,这样做的目的是为了判断是否有必要进入下面的while循环(不停的向后循环看能否匹配?*这种格式,注意:?*代表.*或者[a~z]*),如果p[1]不是*,说明可能是.或者是[a~z],正常进行判断即可,然后把当前位切掉,代表已经匹配完了,带入递归,如果p[1]是*,这里就要使用while进行循环切割跳转,如果s切掉一位还是与p的当前位相等,那么久继续切割,注意:每次切割之后要将?*从p中切掉和s带入递归中进行判断,这里是为了排除.*[a~z]的情况,看.*在哪里结束可以让后面的字符继续匹配,最后如果?*不能匹配接下来的字符串了,那么跳过?*,继续递归
代码演示
public class Solution1 {
public boolean isMatch(String s, String p) {
// 如果正则为空,判断字符串是否为空,不为空,返回null
if (p == null || p.length() == 0) {
return s == null || s.length() == 0;
}
// 如果正则为1,则判断当前位是否为相等,或者p的当前位是'.' 然后在判断s的长度是否为1,如果不是返回false
if (p.length() == 1) {
return s.length() == 1 && (s.charAt(0) == p.charAt(0) || p.charAt(0) == '.') ;
}
// 上面已经判断了p的长度不是1也不是0
if (p.charAt(1) != '*') {
// 在这里判断如果正则字符串p不为空,但是给定字符串s为空的情况
if (s == null || s.length() == 0) {
return false;
}
// 如果长度不是1,判断当前位是否相等,或者正则是. 将当前位减去进行递归
// 注意:这里已经判断和后一位不是*,所以下一位只可能是.或者字母
return (s.charAt(0) == p.charAt(0) || p.charAt(0) == '.')
&& isMatch(s.substring(1), p.substring(1));
}
// 如果s不是null,并且还有长度,&& s的当前位和p的当前位相同,或者p的当前位是.
// 注意:p[1]肯定是*,因为上面已经判断过了,所以0位和1位可能是.*或者[a~z]*
while (s != null && s.length() != 0 && (s.charAt(0) == p.charAt(0) || p.charAt(0) == '.')) {
// 如果在当前s和正则字符切掉的?*还能匹配,这是为了判断.*或者[a~z]*的情况
if (isMatch(s, p.substring(2))) {
return true;
}
// 如果剩余字符串不能和正则切掉?*匹配,那么就切掉s的当前位
s = s.substring(1);
}
// 如果到达了*所能表示的末尾,也就是p[0]重复0个或者多个还是不满足的话,将当前p的0位和1位去掉,在和s带入递归
return isMatch(s, p.substring(2));
}
public static void main(String[] args) {
Solution1 s = new Solution1();
System.out.println(s.isMatch("ab", ".*c"));
}
}