动态规划 | 带有通配符的字符串匹配(浅显易懂)
来源:互联网 发布:塑料水晶高跟鞋淘宝 编辑:程序博客网 时间:2024/03/29 05:20
自己的C++实现包含?和*通配符的程序,肯定有bug,欢迎指出:)
ostream& operator<<(ostream& o, const vector<vector<int> >& v){ for(int i=0; i<v.size(); i++){ vector<int> vv = v[i]; for(int j=0; j<vv.size(); j++){ o<<vv[j]<<" "; } o<<endl; } return o;}int main(int argc, char *argv[]){ QCoreApplication a(argc, argv); string str1, str2; cin>>str1>>str2; vector<vector<int> > array(str1.size()+1, vector<int>(str2.size()+1, 0)); for(int i=0; i<str1.size(); i++){ for(int j=0; j<str2.size(); j++){ //初始化 //判断第一个字符是不是匹配,若匹配则置1,否则置0 if(i==0&&j==0){ if(str1[i]=='*' || str2[j]=='*' || str1[i]=='?' || str2[j]=='?' || str1[i]==str2[j]){ array[i+1][j+1]=1; continue; } else{ cout<<"Not Match!"; return 0; } } //若出现*通配符,则检查左,上和左上三个方向的状态 if(str1[i]=='*' || str2[j]=='*'){ if(array[i][j+1]==1 || array[i+1][j]==1 || array[i][j]==1){ array[i+1][j+1]=1; } } //若出现?通配符,则检查左上的状态 else if(str1[i]=='?' || str2[j]=='?'){ if(array[i][j]==1 || array[i][j]==2){ array[i+1][j+1]=2; } } else if(str1[i]==str2[j]){ if(array[i][j+1]==1 || array[i+1][j]==1 || array[i][j]==1 || array[i][j]==2){ array[i+1][j+1]=1; } } } } int result = array[str1.size()][str2.size()]; if(result==1 || result==2) cout<<"Match!"; else cout<<"Not Match!"; //cout<<array; return 0;}
以下转载自 http://blog.csdn.net/gldemo/article/details/47678159
带有通配符的字符串匹配
一、Leetcode | 44 Wildcard Matching(只有一个字符串包含通配符)
题目很简单,就是说两个字符串,一个含有通配符,去匹配另一个字符串;输出两个字符串是否一致。
注意:’?’表示匹配任意一个字符,’*’表示匹配任意字符0或者多次
首先,我们想到暴力破解。如果从头到尾的破解,到第二个字符时,是否匹配成功取决于第一个字符是否匹配成功! 所以我们想到应该要用到动态规划;
既然用到动态规划,最重要的是设置初值 和找到递推式:
于是,我们开始分析初值怎么设;其实很简单,把这个匹配问题可以想象成一个矩阵dp,纵轴代表含有通配符的匹配字符串s2, 横轴代表要匹配的字符串s1。假设现在s2=”a*b”, s1=”abc” 如图:
对应空位就是截止到当前的 (i,j) 位置,两字符串是否匹配。匹配为 T(true),不匹配为 F(false),最后返回最右下角的值,就是当前两个字符串是否匹配的最终值;
现在我们要做的设置初值,所以我们大可多加一行和一列,来填充初值;s1既然是要匹配的,我们都设为 F(即dp[0][1]=F,dp[0][2]=F,dp[0][3]=F),表示当前还未开始匹配。而s2的初值,我们发现如果星号和a调换位置,星号可以匹配任意字符串,所以dp[i][0]的值取决于该位置是否为星号和上一个位置d[i-1][0]是否为T(其实就是上一个位置是否也是星号),所以我们设置dp[0][0]为 T。所以形成下图:
此时初值已经设置完毕,我们要找到递推式;经局部推算,我们发现递推式应该有两种,一种是当s2的字符是星号,另一种是s2的字符是非星号。
先看星号的情况:当要计算dp[2][1](即要匹配a*和a时),我们发现是取决于dp[1][1](即a和a是否匹配),当要计算dp[2][2] (即要匹配a*和ab时),是取决于dp[2][1] (即a*和a是否匹配)。抽象一下,星号和任意字符(0或多个)都匹配。所以字符串截止到星号匹配的情况,取决于当前位置向上和向左的情况(即可以为0个字符,也可以为多个字符)。所以此时递推式为
再看非星号的情况:当要计算dp[3][2] (即要匹配a*b和ab时),则取决于dp[2][1]和a[3][2] (即a*和a是否匹配,同时b和b是否匹配);所以可以得到递推式 dp[i][j] = dp[i-1][j-1]&&a[i][j]。如图:
最后我们得到了初值和两个递推式,就可以上代码了;
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
PS: 两个字符串都包含通配符的解法
通过上面那个列子,其实就这个问题就很容易想了。
首先就是初值的设置,两个字符串都按上题中的包含通配符的字符串设置初值的方法,根据是否为星号和上一个的状态。
其次就是递推式,它不用变,只是需要同时判断两个字符串中是否都包含通配符。
直接上代码:
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
二、Leetcode | 10 Regular Expression Matching(正则通配符)
这道题是把*的概念变了,它代表匹配星号之前元素的0个或多个。即 c* 带便0个或者多个c。
所以具体代码和思路写到代码注释里了。大家可以对照上面的题看看。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 动态规划 | 带有通配符的字符串匹配(浅显易懂)
- 动态规划 | 带有通配符的字符串匹配(浅显易懂)
- 浅显易懂的动态规划入门
- 带通配符的字符串匹配:动态规划
- 史上最浅显易懂的KMP算法讲解:字符串匹配算法
- 带通配符的字符串匹配问题的动态规划算法
- openjudge 6256 带通配符的字符串匹配(动态规划)
- 带有通配符的两个字符串匹配问题
- 带有通配符的字符串和另一个字符串进行匹配
- 带有通配符的字符串和另一个字符串进行匹配
- 带有通配符的字符串和另一个字符串进行匹配(转载加修改)
- 带有通配符的字符串匹配算法-C/C++
- 带有通配符的字符串匹配算法-C/C++
- 32.3-5带有通配符的匹配(自动机)
- 动态规划——通配符匹配算法
- 动态代理 静态代理 代理模式详解(讲的很好 浅显易懂)
- 浅显易懂的经济学常识
- 浅显易懂的Git教程
- linux c++ + vs2017 + 虚拟机环境
- JFinal中如何重写String?
- MEF学习笔记
- c++ class、struct区别
- 4年工作:从量变到质变(公开版)
- 动态规划 | 带有通配符的字符串匹配(浅显易懂)
- 第一篇博客
- 设在vim自动换行等功能的方法
- 二叉树的递归和非递归遍历(java)
- OpenCV学习笔记(6)图像的缩放
- C++递推算法之菲波拉契数列
- 基于Tcl/Tk语言的自动化测试平台的实现
- 微信小程序wx.getImageInfo()获取图片信息
- UNIX/Linux_C_程序员需要掌握的七种武器