华为OJ的题:
问题描述:在计算机中,通配符一种特殊语法,广泛应用于文件搜索、数据库、正则表达式等领域。现要求各位实现字符串通配符的算法。
要求:
实现如下2个通配符:
*:匹配0个或以上的字符(字符由英文字母和数字0-9组成,不区分大小写。下同)
?:匹配1个字符
输入:
通配符表达式;
一组字符串。
输出:
返回匹配的结果,正确输出true,错误输出false
在OJ里面是初级题。最近脑子很笨,反应不过来。也是在网上看了思想之后才编出来的。
具体思想:
1.由于*可以代替任意字符,所以*先要忽略
2.?可以代替一个字符,所以将它考虑到当中
3.以*为分隔符来分割字符串,现在字符串是一系列的字符。如果第一个字符跟整体匹配上了,下一个字符接着上一个匹配的末尾继续匹配,以此类推,都匹配成功就算匹配成功。
4.字符串的匹配因为涉及到?,不能直接用string的find。所以用kmp算法。
KMP具体来说,就是在原字符串中找到第一个与匹配字符串相同的字母,然后依次匹配若成功则返回,若失败,则记录失败的位置,下次从失败的位置开始匹配。这样可以提高效率。
注:对于?匹配其实没有那么麻烦,只有在if语句中加上一个||就可以了如果匹配字符串中的那个位是?就默认匹配成功。
上代码:
#include <stdio.h> #include <iostream> #include <stack> #include <string> #include <vector> using namespace std; char daxie(char c) { if (c >= 'A'&&c <= 'Z') { c = c - 'A' + 'a'; } return c; } int pipei(string S, string T) { int index = 0; for (int i = index; i < S.size(); i++) { if (S[i] == T[0]||T[0]=='?') { int k; for (k = 0; k < T.size() && k+i <S.size() ; k++) { if (S[k+i] == T[k]||T[k]=='?') { } else { index = k + i; break; } } if (k == T.size() ) { return i; } } } return -1; } int main() { string str1, str2; while (cin >> str1>>str2) { for (int i = 0; i < str1.size(); i++) { str1[i] = daxie(str1[i]); } for (int i = 0; i < str2.size(); i++) { str2[i] = daxie(str2[i]); } vector<string> a; int pos = -1; while ((pos = str1.find('*')) != string::npos) { a.push_back(str1.substr(0, pos)); str1 = str1.erase(0, pos + 1); } a.push_back(str1); for (int i = 0; i < a.size(); i++) { if (a[i] == "") { a.erase(a.begin() + i, a.begin() + i + 1); } } int i; for (i = 0; i < a.size(); i++) { int pos = -1; if ((pos = pipei(str2, a[i])) < 0) { cout << "false" << endl; break; } else { str2 = str2.erase(0, pos + a[i].size()); } } if (i == a.size()) { cout << "true" << endl; } int kk = 0; } return 0; }
注意:此代码是有些问题的。比如你输入*,按道理是都能匹配的,但是有字符串分割没有成功,所以会失败,但是就不更改了。
还有一个问题,虽然华为的系统没有检测,但是还是不能忽略的。
*只能代表数字和字母,并不能匹配除这以外的。(可能是华为的测试样例也没有考虑吧)
所以如果输入*.* 和...也会匹配成功,这是不严谨的。所以说匹配的时候,在跳过的那几个串中要检测有没有*不能替代的字符,如果算不匹配。