今天我们看一道 leetcode hard 难度题目:通配符匹配。
题目
给你一个输入字符串 (s) 和一个字符模式 (p) ,请你实现一个支持 '?' 和 '*' 匹配规则的通配符匹配:
'?'可以匹配任何单个字符。'*'可以匹配任意字符序列(包括空字符序列)。 判定匹配成功的充要条件是:字符模式必须能够 完全匹配 输入字符串(而不是部分匹配)。
示例 1:
输入:s = "aa", p = "a"
输出:false
解释:"a" 无法匹配 "aa" 整个字符串。
思考
最直观的思考是模拟匹配过程,以 s = "abc", p = "abd" 为例,匹配过程是这样的:
"a" 匹配 "a",通过
"b" 匹配 "b",通过
"c" 不匹配 "d",失败
只要匹配过程有任何一个字符匹配失败,则整体匹配失败。如果没有 '?' 与 '*' 号,题目则异常简单,只要一个指针按顺序扫描,扫描过程每个字符必须相等,且同时结束才算成功,否则判断失败。
加上 '?' 依然很简单,因为 '?' 号一定会消耗掉,只是它可以匹配任何字符,所以还是一个指针扫描,遇到 p 中 '?' 号时,跳过判等继续向后扫描即可。
加上 '*' 号时该题成为 hard 的第一个原因。由于 '*' 可以匹配空字符,也可以匹配任意多个字符,所以遇到 p 中 '*' 时有三种处理可能性:
当做没见过
'*',直接判等,不消耗s,并匹配p的下一个字符。此时对应'p'不匹配任何字符。直接消耗掉
'*'判等,同时消耗s与p。此时'*'与'?'的作用等价。不消耗
'*',但是消耗s。此时对应'*'匹配多个字符而可以不消耗自己的特性。
很容易想到写一个递归的实现,代码如下:
function isMatch(s: string, p: string): boolean {
return myIsMatch(s.split(''), p.split(''))
};
function myIsMatch(sArr: string[], pArr: string[]): boolean {
// 如果 s p 都匹配完了,或 p 还剩任意数量的 *,都算匹配通过
if (
(sArr.length === 0 && pArr.length === 0) ||
(sArr.length === 0 && pArr.every(char => char === '*'))
) {
return true
}
// 如果任意一项长度为 0,另一项不为 0,则匹配失败
if (
(sArr.length === 0 &

文章详细解析了LeetCode中一个Hard难度的题目——通配符匹配,讨论了使用模拟匹配和动态规划两种方法。动态规划是解决此问题的关键,尤其是理解*号在匹配过程中的三种可能性,并构建正确的状态转移方程。难点在于从左到右匹配的思维定势以及*号匹配的双向等价性。文章提供了动态规划的解决方案,并指出还有优化空间,如使用滚动数组和提前终止循环。
最低0.47元/天 解锁文章

被折叠的 条评论
为什么被折叠?



