给定一个字符串 (s) 和一个字符模式 § ,实现一个支持 ‘?’ 和 ‘*’ 的通配符匹配。
‘?’ 可以匹配任何单个字符。
‘*’ 可以匹配任意字符串(包括空字符串)。
两个字符串完全匹配才算匹配成功。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/wildcard-matching
不说了,本人就是菜,对着leetcode的反例反复修改。
简洁的大佬答案,请移步:大佬的代码
大佬代码思路是动态规划。
A[i][j]表示是a[i]和b[j]之前的字符串的匹配情况。真则匹配,假则不匹配。
A[i][j]的确定规则如下:
- 当a[i]时?或者非*的其他字符的时候,就检查a[i]和b[j]还有A[i-1][j-1]
- 当a[i]为*的时候,就需要检查A[i-1][j]和A[i-1][j-1]和A[i][j-1]当这三个有一个是1的时候,A[i][j]就是1。
按照类似的思路,可以有如下操作
例如:*a *b adceb
确定A[1][1]的元素内容需要检查a[1],a[1]是a,所以是非*的字符,接着检查A[0][0],可以得到
A[0][0]=1,还需要检查a[1]和b[1],而a[1]和b[1]一个是a一个是b所以并不相等。A[1][1]就可以确定为是0。同理第二行的所有元素都需要和a[1]进行比较,而都不相等,所以可以得到第二行后续全部填入0。
确定A[2][1]的元素需要首先看a[2],可以得到a[2]是*,所以要检查A[1][0],A[2][0],A[1][1]。其中A[2][0]是1,所以要填入1。后续的推导类似。
依次完成整个表格的填写。
输出对应的在后下角的值对应的matched或者not matched就可以了。
以上是整体思路。
如下代码是自己写的,相对不太好看。
for (int i = 1; i < length; i++) {
for (int n = 1; n < lengthb; n++) {
if (a[i]=='?') {
ch[i][n] =ch[i-1][n-1];
}
if (a[i] == '*') {
if (ch[i - 1][n - 1] || ch[i][n - 1] ||ch[i-1][n]) {
ch[i][n] = 1;
}
else {
ch[i][n] = 0;
}
}
if (a[i] != '?'&&a[i] != '*') {
ch[i][n] = ch[i - 1][n - 1]*check(a,b,i,n);
}
}
}
其中check()如下:
int check(char a[20],char b[20],int i,int n) {
if (a[i] == b[n]) {
return 1;
}
return 0;
}
还有一些零碎的个人在实现的过程中的思路。
为了上述过程的顺利实现,需要对第一行和第一列进行初始化操作。
对第一行的初始化相对简单。
- 当a[0]是*的时候,第一行是1。
- 当a[0]是?或者和b[0]相当的时候,第一行只有A[0][0]是1,其余是0。
对第一列进行初始化相对困难一点。可以反向思考,什么时候a[i]需要开始写入0。
- 当a[0]是和b[0]不同的字符的时候
- 当出现过?,其他a[n]全是*,n小于i,并且a[i]是第二个其他字符的时候。
- 当出现过和b[0]同字母,其他a[n]全是*,n小于i,并且a[i]是第二个其他字符的时候。
代码块如下:(ps:修改了好久,主要是初始化问题。还是总体思路不太好的结果)
int flag=1;
if (a[0] == b[0] || a[0] == '?')flag = 0;//如果a[0]是b[0]或者?就更改flag后续只要有非*就填入0
for (; curr < length; curr++) {
if (a[curr] == '*') {
ch[curr][0] = ch[curr - 1][0];
}
else {
if (flag && (a[curr] == b[0] || a[curr] == '?')) {
ch[curr][0] = ch[curr - 1][0];
flag = 0;
}
else {
ch[curr][0] = 0;
}
}
}
总的代码:
#include<stdio.h>
#include<stdlib.h>
int countmuiple(int a, int b);
int countdivi(int a, int b);
int check(char a[20], char b[20], int i, int n);
int main()
{
char a[20];
char b[20];
gets_s(a);
gets_s(b);
int length = strlen(a);
int lengthb = strlen(b);
int curr = 1;
int flag=1;
int ch[20][20] = { 0 };
if (a[0] == '*' || a[0] == '?' || a[0] == b[0]) {
ch[0][0] = 1;
}
else {
ch[0][0] = 0;
}
for (int i = 1; i < lengthb; i++) {
if (a[0] == '*') {
ch[0][i] = 1;
}else{
ch[0][i] = 0;
}
}
if (a[0] == b[0] || a[0] == '?')flag = 0;
for (; curr < length; curr++) {
if (a[curr] == '*') {
ch[curr][0] = ch[curr - 1][0];
}
else {
if (flag && (a[curr] == b[0] || a[curr] == '?')) {
ch[curr][0] = ch[curr - 1][0];
flag = 0;
}
else {
ch[curr][0] = 0;
}
}
}
for (int i = 1; i < length; i++) {
for (int n = 1; n < lengthb; n++) {
if (a[i]=='?') {
ch[i][n] =ch[i-1][n-1];
}
if (a[i] == '*') {
if (ch[i - 1][n - 1] || ch[i][n - 1] ||ch[i-1][n]) {
ch[i][n] = 1;
}
else {
ch[i][n] = 0;
}
}
if (a[i] != '?'&&a[i] != '*') {
ch[i][n] = ch[i - 1][n - 1]*check(a,b,i,n);
}
}
}
if ((length == 0 && lengthb == 0) || (lengthb == 0 && (a[0] == '*' ) && length == 1)) {
printf("matched");
}
else {
if (length > 0 && lengthb > 0 && ch[length - 1][lengthb - 1]) {
printf("matched\n");
}
else {
printf("not matched\n");
}
}
}
int check(char a[20],char b[20],int i,int n) {
if (a[i] == b[n]) {
return 1;
}
return 0;
}
int check(char a[20],char b[20],int i,int n) {
if (a[i] == b[n]) {
return 1;
}
return 0;
}
bool isMatch(char * s, char * p){
int length = strlen(p);
int lengthb = strlen(s);
int curr = 1;
int flag=1;
int ch[1500][1500] = { 0 };
if (p[0] == '*' || p[0] == '?' || p[0] == s[0]) {
ch[0][0] = 1;
}
else {
ch[0][0] = 0;
}
for (int i = 1; i < lengthb; i++) {
if (p[0] == '*') {
ch[0][i] = 1;
}else{
ch[0][i] = 0;
}
}
if (p[0] == s[0]||p[0]=='?'){flag = 0;}
for (; curr < length; curr++) {
if (p[curr] == '*') {
ch[curr][0] = ch[curr - 1][0];
}
else {
if (flag&&(p[curr]==s[0]||p[curr]=='?')) {
ch[curr][0] = ch[curr - 1][0];
flag = 0;
}
else {
ch[curr][0] = 0;
}
}
}
for (int i = 1; i < length; i++) {
for (int n = 1; n < lengthb; n++) {
if (p[i]=='?') {
ch[i][n] =ch[i-1][n-1];
}
if (p[i] == '*') {
if (ch[i - 1][n - 1] || ch[i][n - 1] ||ch[i-1][n]) {
ch[i][n] = 1;
}
else {
ch[i][n] = 0;
}
}
if (p[i] != '?'&&p[i] != '*') {
ch[i][n] = ch[i - 1][n - 1]*check(p,s,i,n);
}
}
}
if ((length == 0 && lengthb == 0)||(lengthb==0&&(p[0]=='*')&&length==1)) {
return true;
}
else {
if (length > 0 && lengthb > 0 && ch[length - 1][lengthb - 1]) {
return true;
}
else {
return false;
}
}
}
最后附上提交结果:
leetcode提交记录
poj的提交记录
代码反思:初始化操作没有和后续的动态规划进行合并,代码不是很简洁,同时给调试带来了很大的麻烦,动归部分反而几乎没有更改。