Problem
LeetCode 10. Regular Expression Matching
1. 题目简述
给出两个字符串s和p,其中s是由小写字母组成,p是由小写字母以及’.’和’*‘组成,’.’和’*‘分别有如下含义:
'.' 可以表示任何单个字符
'*' 可以表示0个或者多个*前面的字符(需要组合起来看,例如:'a*'可以表示0个a或者多个a)
例如:
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".
2. 算法思路
相关问题:
这种题就是做过一次才能有大概思路,也不能保证完全能做出来。
动态规划
首先,对于这道题,直接用动态规划分析,没有为什么。分析p的两种特殊字符,比较麻烦的是’*’,因为我们不知道它会代表几个字符。因此我们只能逐个分析,代表0个,1个……
这里latex写公式有点问题,因此主体逻辑在注释中,其实其中最难理解的部分就是p[j]为’*’时的情况。
这里我们将其分为两种子情况:
s[i] 和 p[j - 1]不匹配:那么dp[i][j] = dp[i][j - 2],这是因为既然二者不匹配的话,说明只能将dp[j - 1]dp[j]这个小pattern当做是空串;
s[i] 和 p[j - 1]匹配:这里我们再去分析其可能的情况。匹配0个s[i],1个s[i],2个s[i]……但是我们仔细一想可以发现,假如说匹配2个及以上个s[i]的话,那么s的前i-1个字符的子串和p的前j个字符的子串也一定是匹配的!这里以两个为例:
s:”acbbbd”
p:”acb*d”
当i = 3时,也就是计算s的子串”acbb”时,当我们匹配到j = 3时,也就是说”acb*”时,我们发现”acb*”和i = 2时的”acb”也是匹配的,因为这里”b*”表示为1个b。换句话说,如果”b*”表示两个及以上的“b”的话,那么s[0, i-1]和p[0, j]也一定是匹配的,因为”b*”表示的重复有很多。
因此对于上面的情况2,我们可以将匹配2个及以上s[i]的情况递推为dp[i - 1][j],因此我们有递推式:
dp[i][j] = dp[i][j - 2] || dp[i][j - 1] || dp[i - 1][j]
三项分别对应0个,1个和多个的情况。
进一步,我们可以将其规约为两项,因为如果*的前一个字符和s[i]相匹配,那么可以匹配0个,1个,2个,3个…对于1个及以上的情况,我们可以将其规约到dp[i-1][j+1]里面,因为这次的的1个,2个,3个等于上次匹配的0个,1个,2个…
dp[i][j] = dp[i][j - 2] || dp[i - 1][j]
参考解析:LeetCode discussion区的大佬解法
1 | class Solution { |