LeetCode-10. Regular Expression Matching(Hard):
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 preceding 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
我的解法:
第一次解得时候就用暴力判断的方法,和第44题不同的是,这道题硬解是能解出来的
class Solution:
def isMatch(self, s, p):
"""
:type s: str
:type p: str
:rtype: bool
"""
sLen = len(s)
pLen = len(p)
if (pLen == 0):
return sLen == 0
if (pLen == 1):
if (p == s) or ((p == '.') and (len(s) == 1)):
return True
else:
return False
#p的最后一个字符不是'*'也不是'.'且不出现在s里,p跟s肯定不匹配
if (p[-1] != '*') and (p[-1] != '.') and (p[-1] not in s):
return False
if (p[1] != '*'):
if (len(s) > 0) and ((p[0]==s[0]) or (p[0]=='.')):
return self.isMatch(s[1:],p[1:])
return False
else:
while (len(s) > 0) and ((p[0]==s[0]) or (p[0]=='.')):
if (self.isMatch(s,p[2:])):
return True
s = s[1:]
return self.isMatch(s,p[2:])
但是因为刚刚学了动态规划,总结到这里就尝试用动态规划解决一下这个问题
首先找一个样例:
s = "mississippi"
p = "mis*is*p*."
列出状态数组dp的值:
s\p | 0 | m | i | s | * | i | s | * | p | * | . |
0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
m | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
i | 0 | 0 | 1 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
s | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
s | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
i | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 1 | 0 |
s | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 1 |
s | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 1 | 1 |
i | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
p | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
p | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
i | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
列出状态转移方程:
dp(0,0)=0;
if p[j]='*', dp(i,j) = dp(i,j-1) || dp(i,j-2) || ( (dp(i-1,j-1) || dp(i-1,j) ) && (s[i] = p[j-1] || p[j-1]='.') )
if p[j]!='*',dp(i,j) = dp(i-1,j-1) && (s[i]=p[j] || p[j]='.')
当然,状态转移方程可能不是一次列出来就考虑到了所有情况,提交之后出现问题再改(上面是改对之后的)
在写代码的过程中还要注意对dp(0,*)和dp(*,0)的初始化,还要考虑i、j减一和减二时的边界问题,另外,注意s、p字符串的下标和dp二维数组的下标是错一位的,要注意减一。
class Solution {
public boolean isMatch(String s, String p) {
int slen = s.length();
int plen = p.length();
int[][] dp = new int[slen+1][plen+1];
//初始化
dp[0][0] = 1;
for(int t=1; t<=slen; t++){
dp[t][0] = 0;
}
for(int t=1; t<=plen; t++){
if(t==1) {
dp[0][t] = 0;
}
else if(t==2) {
if(p.charAt(t-1)=='*') {
dp[0][t] = 1;
}
else {
dp[0][t] = 0;
}
}
else if(p.charAt(t-1) == '*' && t>2 && dp[0][t-2] == 1) {
dp[0][t] = 1;
}
else {
dp[0][t] = 0;
}
}
//根据状态转移方程求dp的所有值
for(int i=1; i<=slen; i++) {
for(int j=1; j<=plen; j++) {
if(p.charAt(j-1) == '*') {
if(j>1) {
dp[i][j] = dp[i][j-1] | dp[i][j-2] | (dp[i-1][j-1] | dp[i-1][j]) & ((s.charAt(i-1)==p.charAt(j-1-1)?1:0) | (p.charAt(j-1-1)=='.'?1:0));
}
else {
dp[i][j] = dp[i][j-1] | (dp[i-1][j-1] & ((s.charAt(i-1)==p.charAt(j-1-1)?1:0) | (p.charAt(j-1-1)=='.'?1:0)));
}
}
else {
dp[i][j] = dp[i-1][j-1] & ((s.charAt(i-1)==p.charAt(j-1)?1:0) | (p.charAt(j-1)=='.'?1:0));
}
}
}
if(dp[slen][plen] == 1) {
return true;
}
else {
return false;
}
}
}