带通配符的字符串匹配:动态规划

来源:互联网 发布:美工注意事项 编辑:程序博客网 时间:2024/04/28 08:21
描述通配符是一类键盘字符,当我们不知道真正字符或者不想键入完整名字时,常常使用通配符代替一个或多个真正字符。通配符有问号(?)和星号(*)等,其中,“?”可以代替一个字符,而“*”可以代替零个或多个字符。你的任务是,给出一个带有通配符的字符串和一个不带通配符的字符串,判断他们是否能够匹配。例如,1?456 可以匹配 12456、13456、1a456,但是却不能够匹配23456、1aa456;2*77?8可以匹配 24457798、237708、27798。输入输入有两行,每行为一个不超过20个字符的字符串,第一行带通配符,第二行不带通配符输出如果两者可以匹配,就输出“matched”,否则输出“not matched”样例输入1*456?11111114567样例输出matched总时间限制:1000ms内存限制:65536kB

CS的模拟赛里有这道题,当时花了40分钟,用记忆化搜索AC了此题。当时由于AK(了三道水题)而感到很得意,没有虚心学习轮廓更清晰的算法实现。今天中国大学先修课计算概论考试的压轴题是这道,没做出来。算是一个教训吧。最终以6道题AC结束了今天的考试。恭喜DYX、WZH、WNX同学AK。

可以用DP。注意*考虑三种情形:匹配0个字符、1个字符、多个字符。设f[i][j]为第一个字符串的前缀i是否能和第二个字符串的前缀j匹配,则这三种情况分别对应f[i-1][j]f[i-1][j-1]f[i][j-1]。再者,边界的处理要慎重。如果把前缀0作为空串,那么空串能和空串、*匹配。

#include <cstdio>#include <cstring>using namespace std;char s[22], t[22];bool f[22][22];int main(){    scanf("%s %s", s+1, t+1);    int m = strlen(s+1), n = strlen(t+1);    f[0][0] = true;    for (int i = 1; s[i] == '*'; ++i)        f[i][0] = true;    for (int i = 1; s[i]; ++i)        for (int j = 1; t[j]; ++j) {            if (s[i] == '?')                f[i][j] = f[i-1][j-1];            else if (s[i] == '*')                f[i][j] = f[i-1][j] || f[i-1][j-1] || f[i][j-1];            else                f[i][j] = f[i-1][j-1] && (s[i] == t[j]);        }    puts(f[m][n] ? "matched" : "not matched");    return 0;}

附上记忆化搜索:

#include <cstdio>#include <cstring>using namespace std;char s[21], t[21];int ans[21][21];int m, n;bool search(int i, int j){    if (i == m+1 && j == n+1)        return true;    if (i == m+1 || j == n+1)        return false;    int& a = ans[i][j];    if (a != -1)        return a;    if (s[i] == '?')        return a = search(i+1, j+1);    if (s[i] == '*') {        if (search(i, j+1))            return a = true;        if (search(i+1, j))            return a = true;        return a = search(i+1, j+1);    }    if (s[i] != t[j])        return a = false;    return a = search(i+1, j+1);}int main(){    memset(ans, -1, sizeof(ans));    scanf("%s %s", s, t);    m = strlen(s);    n = strlen(t);    if (search(0, 0))        puts("matched");    else        puts("not matched");    return 0;}

初赛、大学先修课两连挂,算是浇了一盆让人清醒的冷水。

0 0
原创粉丝点击