在Linux Shell命令下通配符'*'表示0个或多个字符,‘?’表示一个字符 现编写一段代码实现通配符'*'和'?'的功能。
输入描述:
第一行输入通配字符串 第二行输入要匹配查找的字符串
输出描述:
输出所有匹配的字串起始位置和长度,每行一个匹配输出 如果不匹配,则输出 -1 0 如果有多个按照起始位置和长度的正序输出。
示例1
输入
*.com shopeemobile.com
输出
0 16 1 15 2 14 3 13 4 12 5 11 6 10 7 9 8 8 9 7 10 6 11 5 12 4
【思路】
关于通配符匹配,对于匹配串S1 和 模式串 T1 其基本思路是:
if(T[i]=='?' || T[i]==S[j])
dp[i][j]=dp[i-1][j-1];
if(T[i]=='*')
dp[i][j]=dp[i-1][j]||dp[i][j-1];
但本题有所不同,需要找出所有可以匹配的位置
采取枚举匹配串方式,时间复杂度很大
基本策略:
枚举源匹配串的起点,由 枚举点开始的串 和 模式串 做匹配计算
采取搜索的策略:
DFS(int i,int j) 表示当前研究的是 匹配串i位置 和 模式串的j位置 那么:
- 若j==t.length() =》 那么模式串搜索完毕=》符合要求填入结果=》return
- 若i==s.length() =》 那么匹配串搜索完毕 =》return
- 若s[i]==t[j] 或者 t[j]=='?' =>搜索下一组位置 DFS(i+1,j+1)
- 若t[j]=='*' 那么搜索 DFS(i+1,j) 以及 DFS(i,j+1)
- 否则 s[i]!=t[j] 那么直接返回
该方法和采取动态规划方法对比? 采取传统动态规划,空间超
该方法空间开销更小,并且由于中间有及时剪切,即如果可以判断一定无法匹配,那么及时返回
剪切点:
初始化进入 DFS时,发生在当且仅当下列三种情况:
s[0]==t[0] 两者第一个字母相等时=>可进入搜索
t[0]=='?' 模式串第一个字母为? =>可进入搜索
t[0]=='*' 模式串第一个字母为* =>可进入搜索
具体代码实现:
string s, t;
set<int> S; //存放结果
//从待匹配串i开始 模式串j开始 dfs
void DFS(int i, int j) {
if (j == t.length()) //模式串搜索到最后节点 那么搜索成功
{
S.insert(i);
return;
}
if (i == s.length())
return;
if (s[i] == t[j] || t[j]=='?') //两者相等 那么往后
DFS(i + 1, j + 1);
else if ( t[j] == '*') //如果模式串 当前节点为*
{
DFS(i, j + 1); //那么有种搜索方向
DFS(i + 1, j);
}
}
int main() {
cin >> t >> s;
bool flag = false;
for (int i = 0; i < s.length(); i++) {
if (s[i] == t[0] || t[0] == '*' ||t[0]=='?') //根据两者首字母判断是否进入DFS搜索
{
DFS(i, 0);
if (!S.empty())
{
flag = true;
for (auto item:S)
cout << i << " " <<item - i << endl;
}
S.clear();
}
}
if (!flag)
cout << -1 << " " << 0 << endl;
return 0;
}