華為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; }
注意:此代碼是有些問題的。比如你輸入*,按道理是都能匹配的,但是有字符串分割沒有成功,所以會失敗,但是就不更改了。
還有一個問題,雖然華為的系統沒有檢測,但是還是不能忽略的。
*只能代表數字和字母,並不能匹配除這以外的。(可能是華為的測試樣例也沒有考慮吧)
所以如果輸入*.* 和...也會匹配成功,這是不嚴謹的。所以說匹配的時候,在跳過的那幾個串中要檢測有沒有*不能替代的字符,如果算不匹配。