内容介绍
给你一个输入字符串 (
s
) 和一个字符模式 (p
) ,请你实现一个支持'?'
和'*'
匹配规则的通配符匹配:
'?'
可以匹配任何单个字符。'*'
可以匹配任意字符序列(包括空字符序列)。判定匹配成功的充要条件是:字符模式必须能够 完全匹配 输入字符串(而不是部分匹配)。
示例 1:
输入:s = "aa", p = "a" 输出:false 解释:"a" 无法匹配 "aa" 整个字符串。示例 2:
输入:s = "aa", p = "*" 输出:true 解释:'*' 可以匹配任意字符串。示例 3:
输入:s = "cb", p = "?a" 输出:false 解释:'?' 可以匹配 'c', 但第二个 'a' 无法匹配 'b'。提示:
0 <= s.length, p.length <= 2000
s
仅由小写英文字母组成p
仅由小写英文字母、'?'
或'*'
组成
完整代码
bool isMatch(char* s, char* p) {
int m = strlen(s);
int n = strlen(p);
int dp[m + 1][n + 1];
memset(dp, 0, sizeof(dp));
dp[0][0] = true;
for (int i = 1; i <= n; ++i) {
if (p[i - 1] == '*') {
dp[0][i] = true;
} else {
break;
}
}
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
if (p[j - 1] == '*') {
dp[i][j] = dp[i][j - 1] | dp[i - 1][j];
} else if (p[j - 1] == '?' || s[i - 1] == p[j - 1]) {
dp[i][j] = dp[i - 1][j - 1];
}
}
}
return dp[m][n];
}
思路详解
思路详解:
-
初始化:
- 首先计算两个字符串的长度
m
和n
。 - 创建一个二维数组
dp
,大小为(m + 1) x (n + 1)
,用于存储子问题的解。 - 初始化
dp[0][0]
为true
,表示空字符串与空模式字符串匹配。
- 首先计算两个字符串的长度
-
处理模式字符串中的星号
*
:- 对于模式字符串
p
中的每个星号*
,有两种匹配方式:- 匹配任意字符(包括空字符)。
- 匹配前面的一个字符。
- 因此,对于每个星号,
dp[i][j]
可以是dp[i][j-1]
或者dp[i-1][j]
。
- 对于模式字符串
-
处理模式字符串中的问号
?
和普通字符:- 模式字符串中的问号
?
匹配任意字符。 - 普通字符需要与字符串中的对应字符相匹配。
- 因此,对于每个字符,
dp[i][j]
可以是dp[i-1][j-1]
。
- 模式字符串中的问号
-
构建动态规划表:
- 使用两层循环遍历字符串
s
和模式字符串p
。 - 对于每个字符,根据上述规则更新
dp[i][j]
。
- 使用两层循环遍历字符串
-
返回结果:
- 遍历结束后,
dp[m][n]
存储了s
和p
是否匹配的结果。 - 返回
dp[m][n]
的值。
- 遍历结束后,
这个算法的时间复杂度为 O(m * n),其中 m 是字符串 s
的长度,n 是模式字符串 p
的长度。空间复杂度也为 O(m * n),因为需要一个二维数组来存储中间结果。
知识点精炼
-
动态规划:
- 动态规划是一种优化算法的方法,通过将问题分解为更小的子问题来避免重复计算。
- 在本例中,通过构建一个二维数组
dp
来存储子问题的解,从而实现高效的模式匹配。
-
二维数组:
- 二维数组是一个由多个一维数组组成的数组,每个一维数组称为矩阵中的一个“行”。
- 在本例中,使用二维数组
dp
来存储子问题的解,其中dp[i][j]
表示字符串s
的前i
个字符与模式字符串p
的前j
个字符是否匹配。
-
字符串长度获取:
- 使用
strlen
函数获取字符串的长度,这是解决字符串匹配问题时的一个基础操作。
- 使用
-
字符串匹配:
- 判断字符串
s
的当前字符与模式字符串p
的当前字符是否匹配。 - 处理模式字符串中的星号
*
和问号?
。
- 判断字符串
-
指针的使用:
- 动态分配的内存块通过指针来访问,需要确保指针指向的有效性。
-
循环结构:
- 使用两层循环遍历字符串
s
和模式字符串p
,实现动态规划表的构建。
- 使用两层循环遍历字符串
-
边界条件处理:
- 在函数开始时初始化
dp[0][0]
为true
,表示空字符串与空模式字符串匹配。 - 在处理模式字符串中的星号
*
时,对于每个星号,dp[i][j]
可以是dp[i][j-1]
或者dp[i-1][j]
。
- 在函数开始时初始化
-
字符串匹配逻辑:
- 对于模式字符串中的问号
?
和普通字符,dp[i][j]
可以是dp[i-1][j-1]
。
- 对于模式字符串中的问号
-
返回结果:
- 遍历结束后,
dp[m][n]
存储了s
和p
是否匹配的结果。 - 返回
dp[m][n]
的值。
- 遍历结束后,
这些知识点涵盖了动态规划、二维数组、字符串操作、指针的使用、循环结构等 C 语言基础内容