题目
在计算机中,通配符是一种特殊语法,广泛应用于文件搜索、数据库、正则表达式等领域。让我们来学习通配符的匹配规则:
- ‘*’ 符号代表匹配 0 个或以上的数字或字母;
- ‘?’ 符号代表匹配 1 个数字或字母;
- 小写字母字符代表匹配自身和自身的大写字母形态;
- 大写字母字符代表匹配自身和自身的小写字母形态;
- 其他字符代表匹配自身。
现在,对于给定的通配符字符串 s 和目标字符串 p,不考虑大小写,请判断 s 是否可以匹配得到 p。如果可以,输出 true;否则,输出 false。
在本题中,给定的字符串由 ASCII 码在 33 到 126 范围内的可见字符构成。
示例
示例1
输入:z
zz
输出:false
示例2
输入:Z*
zz
输出:true
说明:在这个样例中,‘*’ 匹配 ‘z’。注意,由于不区分大小写,‘Z’ 可以匹配 ‘z’。
示例3
输入:**Z
0QZz
输出:true
说明:在这个样例中,其中一种匹配方法是:第一个 ‘*’ 匹配 "0Q";第二个 ‘*’ 匹配 ‘Z’;第三个 ‘Z’ 匹配 ‘z’。
示例4
输入:??**
zz
输出:true
说明:‘*’ 可以匹配 0 个字符。
示例5
输入:HH?*
HH##1
输出:false
说明:可被 ‘*’ 和 ‘?’ 匹配的字符不包含 ‘#’。
分析
动态规划法
具体步骤
1. 定义状态
设 dp[i][j] 表示模式串 s 的前 i 个字符和目标字符串 p 的前 j 个字符是否匹配。dp[i][j] 为 true 表示匹配成功,为 false 表示匹配失败。
2. 初始化
dp[0][0] = true:空字符串和空模式串是匹配的。
对于模式串 s 以 * 开头的情况,由于 * 可以匹配 0 个字符,所以 dp[i][0] 取决于 dp[i - 1][0]。即如果 s 的前 i - 1 个字符组成的模式串能匹配空字符串,那么加上一个 * 后依然能匹配空字符串。
3. 状态转移方程
在填充 dp 数组时,根据 s[i - 1] 的不同情况进行讨论:
- 当
s[i - 1]为*时:*可以匹配 0 个字符,此时dp[i][j]取决于dp[i - 1][j],即忽略当前的*字符,看s的前i - 1个字符是否能匹配p的前j个字符。*也可以匹配 1 个或多个字符,此时dp[i][j]取决于dp[i][j - 1],即让*多匹配一个p[j - 1]字符,看s的前i个字符是否能匹配p的前j - 1个字符。- 所以
dp[i][j] = dp[i - 1][j] || dp[i][j - 1]。
- 当
s[i - 1]为?时:?只能匹配 1 个数字或字母。因此,只有当p[j - 1]是数字或字母时,dp[i][j]才取决于dp[i - 1][j - 1],即看s的前i - 1个字符和p的前j - 1个字符是否匹配。
- 当
s[i - 1]为普通字符时:- 普通字符不区分大小写进行匹配。将
s[i - 1]和p[j - 1]都转换为小写后进行比较,如果相等且dp[i - 1][j - 1]为true,则dp[i][j]为true。
- 普通字符不区分大小写进行匹配。将
最终结果存储在 dp[m][n] 中,其中 m 是模式串 s 的长度,n 是目标字符串 p 的长度。如果 dp[m][n] 为 true,则表示模式串 s 能匹配目标字符串 p;否则,不能匹配。
时间复杂度:O(),其中
是模式串
s 的长度, 是目标字符串
p 的长度
空间复杂度:O()
#include <bits/stdc++.h>
using namespace std;
// 判断 s 是否能匹配 p
bool isMatch(const string& s, const string& p) {
int m = s.length();
int n = p.length();
vector<vector<bool>> dp(m + 1, vector<bool>(n + 1, false));
// 空字符串和空模式串匹配
dp[0][0] = true;
// 处理模式串以 * 开头的情况
for (int i = 1; i <= m; ++i) {
if (s[i - 1] == '*') {
dp[i][0] = dp[i - 1][0];
}
}
// 填充 dp 数组
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
if (s[i - 1] == '*') {
// * 匹配 0 个或多个数字或字母
dp[i][j] = dp[i - 1][j] || dp[i][j - 1];
} else if (s[i - 1] == '?') {
if (isalnum(p[j - 1])) {
// ? 匹配 1 个数字或字母
dp[i][j] = dp[i - 1][j - 1];
}
} else {
if (tolower(s[i - 1]) == tolower(p[j - 1])) {
// 普通字符匹配自身及大小写形式
dp[i][j] = dp[i - 1][j - 1];
}
}
}
}
return dp[m][n];
}
int main() {
string s, p;
cin >> s >> p;
if (isMatch(s, p)) {
cout << "true" << endl;
} else {
cout << "false" << endl;
}
return 0;
}
知识充电
isalnum() 函数
isalnum 是 C 和 C++ 标准库中的一个函数,主要用于判断一个字符是否为字母(大写或小写)或者数字。
C 中的 isalnum 函数
#include <ctype.h>
int isalnum(int c);
C++ 中的 isalnum 函数
#include <cctype>
int isalnum(int c);
如果 c 是字母(大写字母 A - Z 或者小写字母 a - z)或者数字(0 - 9),函数返回一个非零值(通常为一个正整数,表示真);如果 c 不是字母或数字,则返回 0(表示假)。
890

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



