05 August 2008
Given an input string (
) and a pattern (1
s
), implement regular expression matching with support for 1
p
and 1
'.'
.1
'*'
1
2
'.' Matches any single character.
'*' Matches zero or more of the preceding element.
The matching should cover the entire input string (not partial).
Note:
1
s
could be empty and contains only lowercase letters 1
a-z
.1
p
could be empty and contains only lowercase letters 1
a-z
, and characters like 1
.
or 1
*
.Example 1:
1
2
3
4
5
Input:
s = "aa"
p = "a"
Output: false
Explanation: "a" does not match the entire string "aa".
Example 2:
1
2
3
4
5
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:
1
2
3
4
5
Input:
s = "ab"
p = ".*"
Output: true
Explanation: ".*" means "zero or more (*) of any character (.)".
Example 4:
1
2
3
4
5
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:
1
2
3
4
Input:
s = "mississippi"
p = "mis*is*p*."
Output: false
求两个字符串是否能完全cover。跟44-Wildcard Matching类似,*的意思略有不同,这道题*表示0个,1个或者多个前面的字符(包括’.’),因此a*b可以表示b,ab或aaab,即任意个a。
1)递归的办法,递归过程中的三种情况:
I - 如果p为空,s也为空,返回true,否则返回false,此为基线条件;
II - p和s不为空,且p的第二个字符为*,因为*之前的字符可以0个或任意正整数个,所以首先用递归调用*代表0的情况,也就是直接把*和它之前的这两个字符去掉再和s比较;而如果当s的第一个字符和p的第一个字符相同,或者p第一个字符等于‘.’(仅代表任意1个字符,可以认为.==s.charAt(0)),把s去掉首字符并递归检查。
III - p和s不为空,且递归过程中p的第二个字符不为*,那就如同正常字符串一样比较第一个字符,然后对后面的字符串调用递归。
2) DP的方法
如果能写成递归,基本就能改成动态规划,因为是两个字符串,这里需要声明一个二维数组布尔数组dp[i][j]
dp[i][j]:表示字符串中s中的前i个字符与字符串p中的前j个字符是否能够匹配。如果能匹配则为true,反之为false。
假如已经算出了前i-1个字符与前j-1个字符的匹配情况了,那如何计算dp[i][j]呢?
对于 ‘.’ 和 ‘*‘的处理
由于’.’ 和 ‘*‘都是在p中,所以
递归
1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public boolean isMatch(String s, String p) {
if (p.length() == 0) {
return s.length() == 0;
}
if (p.length() > 1 && p.charAt(1) == '*') {
return isMatch(s, p.substring(2)) || (s.length() != 0 && (s.charAt(0) == p.charAt(0) || p.charAt(0) == '.') && isMatch(s.substring(1), p));
} else {
return s.length() != 0 && (s.charAt(0) == p.charAt(0) || p.charAt(0) == '.') && isMatch(s.substring(1), p.substring(1));
}
}
}
DP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution {
public boolean isMatch(String s, String p) {
int lenS = s.length(), lenP = p.length();
boolean[][] dp = new boolean[lenS + 1][lenP + 1]; //多一个初始状态,都为0的情况
dp[0][0] = true;
for (int j = 2; j <= lenP; j++) { // 先把"*"处理了
if (p.charAt(j - 1) == '*') {
dp[0][j] = dp[0][j - 2];
}
}
for (int i = 1; i <= lenS; i++) {
for (int j = 1; j <= lenP; j++) {
if (match(s.charAt(i - 1), p.charAt(j - 1))) { // 前面两个字符相匹配
dp[i][j] = dp[i - 1][j - 1];
} else if (p.charAt(j - 1) == '*') { // p中前面一个字符为'*',分两种情况
dp[i][j] = dp[i][j - 2]; // 情况1
if (match(s.charAt(i - 1), p.charAt(j - 2))) { // 情况2
dp[i][j] |= dp[i - 1][j]; // |=表示可能dp[i][j]之前'*'处理过
}
}
}
}
return dp[lenS][lenP];
}
private boolean match(char a, char b) {
return a == b || b == '.';
}
}