题目大意是匹配一个阉割版的正则表达式。’.’表示匹配任何字符,’*’表示匹配0个或任意个’*’之前的字符。设s是要匹配的字符串,长度为m;设p是模式串,长度为n。
下面的例子是题目中给出的。
isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "a*") → true
isMatch("aa", ".*") → true
isMatch("ab", ".*") → true
isMatch("aab", "c*a*b") → true
开始我还把题目看错了,我以为*就是和命令行下的*一个意思,匹配任意个字符。结果看到isMatch(“aab”, “c*a*b”) → true还纳闷了半天。
拿到题目先想到贪心法,即看到*的时候就匹配尽量多的字符,但是不对。假设我们有aaaaaaaaa和a*a。用贪心法在遇到第一个*的时候就把a全匹配完了,模式串中剩下一个a没地方匹配了。
一个暴力的方法就是回溯搜索了,从多到少尝试*能匹配的字符。但是显然时间复杂度太高了。极端情况要枚举O(m^n)种情况。回溯为什么慢?因为回溯重复计算了状态树中的节点,状态是什么?当前s[0..i-1]和p[0..j-1]匹配成功。并且我们不需要管这当中是如何匹配的,这就是动态规划中的无后效性。所以可以用动态规划解决这题。
设bool f[i][j]表示s[0..i-1]和p[0..j-1]是否匹配成功。则分有无*两种情况讨论。
当p[j-1]!='*'时
f[i][j] = f[i-1][j-1] p[j-1]和s[i-1]匹配,消耗s和p的一个字符
= false Otherwise
当p[j-1]='*'时
f[i][j] = f[i-1][j]||f[i][j-2] p[j-2]和s[i-1]匹配。消耗s的一个字符,或者也可以选择不匹配p[j-2]和s[i-1],消耗掉p的两个字符
= f[i][j-2] 否则消耗掉p的两个字符
在进行动态规划之前还应该注意边界条件:
f[0][0]=true 空串和空串匹配是成功的
f[i][0]=false, i=1..n 模式串为空时匹配任何非空字符串都失败
f[0][j]=f[0][j-2], j>1且p[j-1]='*' 如果s是空串的话必须*才可以匹配
=false 否则无法匹配空串
最后返回f[m][n]即可。