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

描述

通配符是一类键盘字符,当我们不知道真正字符或者不想键入完整名字时,常常使用通配符代替一个或多个真正字符。通配符有问号(?)和星号(*)等,其中,“?”可以代替一个字符,而“*”可以代替零个或多个字符。

你的任务是,给出一个带有通配符的字符串和一个不带通配符的字符串,判断他们是否能够匹配。

例如,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;
}

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

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值