输入:s = "aa", p = "a"
输出:false
解释:"a" 无法匹配 "aa" 整个字符串。
输入:s = "aa", p = "a*"
输出:true
解释:因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。
输入:s = "ab", p = ".*"
输出:true
解释:".*" 表示可匹配零个或多个('*')任意字符('.')。
题解
两套做法,特定针对这道题的 DP 方法和正则表达式匹配实现的一般方式。第二种很复杂,可以看看这个 题解 了解一下。这里主要针对第一种方法给出题解。
这个问题是使用动态规划的一个经典问题,状态表示使用 f[i][j]
(i <= n, j <= m
),表示 s[i...end]
和 p[j...end]
两个字符串是否能匹配成功。分成几种情况来看:
若 s[i] == p[j] || p[j] == '.'
且 p[j + 1] != '*'
,那么表示当前位置匹配,我们只需要去看下一个位置是否匹配即可,即 f[i][j] = (p[j] == '.' || s[i] == p[j]) && match(i + 1, j + 1)
。
若 p[j + 1] == '*'
,那 '*'
对应的可能是 0 个或是多个 p[j]
字符,则有 f[i][j] = match(i, j + 2) || ((p[j] == '.' || s[i] == p[j]) && match(i + 1, j))
。match(i, j + 2)
表示匹配 0 个,后半部分表示匹配多个,而匹配多个可以是逐个匹配,因此匹配 i + 1
的位置即可。
处理边界情况:当 s[i...end]
和 p[j...end]
均为空串时,匹配成功 f[n][m] = true
;当子串匹配结束时 j == m
,目标串也应该匹配到结束 i == n
。
为了避免在匹配时重复搜索 f[i][j]
使用记忆化搜索进行优化。