2021-06-02 通配符匹配 LeetCode44

给定一个字符串 (s) 和一个字符模式 (p) ,实现一个支持 '?' 和 '*' 的通配符匹配。

'?' 可以匹配任何单个字符。
'*' 可以匹配任意字符串(包括空字符串)。
两个字符串完全匹配才算匹配成功。

说明:

s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 ? 和 *。

利用动态规划解决问题:
我们来看这样一个表

其中,横轴为string s,纵轴为pattern p。p行s列。
这个表第(m,n)个格子的意义是:【p从0位置到m位置】这一整段,是否能与【s从0位置到n位置】这一整段匹配。

也就是说,如果表格的下面这一个位置(p[3]m[4]即为dp[3][4])储存的是T(True):
说明,"adcb"和"a*b"这一段是可以匹配的,你不用管前面发生了什么,你只要知道,这两段是匹配的,这就是动态规划为什么很棒棒。


好,我们回到最初的起点。那么我们如何在这个表格上愉快地行走呢?
我在(START,START)这个位置放了一个T,这就是我们开始行走的位置
只有在T时才能继续往下走


那么从T可以往哪个方向走?
这道题是一个字符串匹配题,那字符串匹配肯定是不能回头的,你不可能在"abcde"里面倒着走,比如从e走到d。


这个“不能倒着走”的规定,反映到我们的表格当中,就是只能往右下角走(往右走、往下走也是有可能的,待会儿我们再说;反正左、上、左上角是不可能的,因为不能倒着走!)


往右下角走,我来举个例子,比如从刚才的初始位置出发,往右下角走一格,来到(a,a)这个位置,发现新引入的这两个字母正好匹配,于是我们在这里记录一个“T”。

如果p里只有字母,没有"*"和"?"这两个东西,每次你只要从原来T的某个格子往右下角走一格,如果新引入的两个字母正好匹配,你就可以在新的格子里记录一个T。


再敲一次黑板:只能从T的格子走,如果某个格子里没有东西(即False),你是不可以从那里出发的。

下面我们来介绍"*"和"?"
我为什么在标题里称这个表格为一个棋盘,是因为我觉得这像是一个下棋游戏
我们知道,中国象棋里每个棋子的功能都不同,像小兵每次只能直走一格,但车却可以直走任意格,还有的棋子则能跳着走
我们这里,普通字母如a、b就像是小兵角色,遇到他们只能右下走一格,走完这一步后判断新引入两个字母是否匹配才能记录T;
而"*"和"?"则是有特殊技能的角色!


角色:"*"
特技:铲平道路
描述:如果这一行是"*",可以从上一行的任意T出发,向下一格后、向右铲平这一行

示例:

所到之处,皆为平地
"*"可以从原来T向正下方走的原因:星号可以匹配空串
"*"可以铲平所有右边道路的原因:星号可以匹配任意长度字符串
大家可以品一品这两个原因。

在讲解另一个狠角色"?"之前,我们再往下走两步,巩固一下之前的知识。
接下来我们在pattern里遇到了一个b,它是一个普通字母,所以只能从上一行某个T往右下角走到达,而且字母匹配才能记录T,于是我们发现可以走这两步:


接下来,"?"隆重登场了


角色:"?"
特技:狸猫换太子
描述:如果这一行是"?",从上一行某个T也只能向右下角走,但不必匹配字母就能记录T
示例:


只要有T就可以直接往右下角走一格,不用在意字母。这里太子“e”被狸猫"?"抵消了

wow,一下子来到了最后一格,小兵走一格就可以liao


要判定是否成功匹配,只要看一个格子!!如果最最右下角的格子是T,那就是匹配成功了,不用在意之前到底发生了什么
所以我们成功了,撒花✿✿ヽ(^▽^)ノ✿

举个例子,像这种情况(我把s的最后一个字母b换成了e)就是不成功了:

总结:

多补一行一列,从start,start开始,所以是plen+1行,slen+1列。

s都为字母

p为字母时,T只能朝右下角判断,匹配为T,不匹配空

p为*时,上一行的T可向正下走一格,再向右走无穷格,不用判断匹配

p为?时,所有T都可向右下角走一格,不用判断匹配

class Solution {
public:
    bool isMatch(string s, string p) {
        s=s+'a';//应付s是空串
        p=p+'a';
        int slen=s.size(),plen=p.size();
        vector<vector<int>>dp(plen+1,vector<int>(slen+1,0));//p+1行,s+1列
        dp[0][0]=1;
        for(int i=1;i<=plen;++i){
            int path=0;//标记是否*让此行通
            for(int j=1;j<=slen;++j){
                if(p[i-1]=='*'&&dp[i-1][j-1]==1){//如果此行是*,上一行某列有T
                    path=1;//标记此行之后都通
                    dp[i][j-1]=1;//上一行某列T的正下都变T
                }
                else if(p[i-1]=='?'||s[j-1]==p[i-1]){//此行是问号或者此行和要比较的列对上
                        dp[i][j]=dp[i-1][j-1];//此行变成左上角(T或F),左上角是F不能变T
                }
                if(path==1){//如果此行通
                    dp[i][j]=1;//此行j列通
                }
            }
        }
        return dp[plen][slen];
    }
};

作者:xiao-yan-gou
链接:https://leetcode-cn.com/problems/wildcard-matching/solution/yi-ge-qi-pan-kan-dong-dong-tai-gui-hua-dpsi-lu-by-/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

在rt-thread,可以通过使用通配符匹配文件名来搜索文件系统的文件。具体实现方法如下: 1. 编写一个递归函数,遍历文件系统的所有文件和目录。 2. 对于每个目录,递归调用该函数,直到找到匹配的文件。 3. 对于每个文件名,通过strcmp函数来比较文件名和通配符,查看是否匹配。 4. 在匹配的情况下,记录下该文件的路径,同时继续搜索其他的文件和目录。 5. 最终得到所有匹配的文件路径,返回给调用者。 例如,可以使用以下代码实现通配符匹配: ```c /* 递归搜索文件系统匹配的文件 */ int find_files(const char *path, const char *pattern, char file_list[][MAX_FILE_NAME_LEN], int *index){ struct dirent *dir; DIR *d = opendir(path); if(d){ while((dir = readdir(d)) != NULL){ /* 获取文件名 */ char filename[MAX_FILE_NAME_LEN]; strcpy(filename, dir->d_name); /* 忽略父目录和当前目录 */ if(strcmp(filename, "..") == 0 || strcmp(filename, ".") == 0) continue; char filepath[MAX_FILE_NAME_LEN]; snprintf(filepath, MAX_FILE_NAME_LEN, "%s/%s", path, filename); if(dir->d_type == DT_DIR){ /* 处理目录 */ find_files(filepath, pattern, file_list, index); }else{ /* 处理文件 */ if(match(pattern, filename)){ snprintf(file_list[*index], MAX_FILE_NAME_LEN, "%s/%s", path, filename); (*index)++; } } } closedir(d); } return 0; } /* 比较文件名和通配符是否匹配 */ int match(const char *pattern, const char *filename){ if(!*pattern && !*filename) /* 如果pattern和filename都为空,则匹配 */ return 1; if(*pattern == '*' && *(pattern+1) != '\0' && !*filename) return 0; if(*pattern == '?' || *pattern == *filename) return match(pattern+1, filename+1); if(*pattern == '*') return match(pattern+1, filename) || match(pattern, filename+1); return 0; } ``` 该代码使用了递归方法来遍历文件系统的所有文件和目录。对于每个文件名和通配符,使用strcmp函数来进行比较。如果匹配,则记录下该文件的路径,并继续搜索其他的文件和目录。最终得到所有匹配的文件路径,返回给调用者。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值