力扣第十題題解
思路
問題描述就不寫了,直接放地址leecode
第一個問題
很簡單的想法就是使用雙指針,但是雙指針存在問題比如這個用例
aaa a*a
第一個a*
會盡可能多的匹配,然後就把aaa
匹配完了。
正確的應該是a*
匹配兩個a
,既然如此,就用遞歸,每一種情況都確保考慮到,匹配零個,匹配一個,匹配兩個...一直匹配到無法繼續找到能和當前pattern 匹配的字符。
第二個問題
存在a*
和.*
的特殊形式,這種時候但看a
和.
是沒有意義的,乾脆把a*
變成A
,.*
變成:
,因爲通過題目描述可知只有小寫字母,句號和星號。
如果題目改變,pattern 含有的信息增多,比如增加了?
,就需要使用更多的變換方式,或者使用面向對象(當前不用考慮)。
第三個問題
有一步沒有添加字符串索引判斷,導致異常,力扣使用的是AddressSanitizer
判斷的,但是錯誤頁面含有的信息很少,只好自己再電腦上測試,但是這個不支持Windows ,只好使用Linux子系統測試。
g++ -fsanitize=address -std=c++11 xxx.cpp -o xxx
顯示出了錯誤信息,但是沒有行數,像這樣
10_back+0x482c
這種的有點看不懂,將命令改爲
g++ -fsanitize=address -std=c++11 xxx.cpp -g -o xxx
,添加了-g
。還有一個參數,-fno-omit-frame-pointer
,想要了解更多,可以看這個Optimize-Options(當前不用瞭解)。
xxx.cpp:47
代碼
增加了一個緩存,存儲已經匹配過的數據。
cache[i][j]代表的是pattern.substr(j) 是否能夠匹配str.substr(i)。
初始化爲u
,如果能夠匹配改爲y
,如果不能匹配,改爲爲n
。
class Solution {
public:
vector<vector<char>> *cache = nullptr;
bool isMatch(string str, string pattern) {
vector<char> newPattern;
delete cache;
cache = new vector<vector<char>>();
for (int i = 0; i < pattern.length(); i++) {
char current = pattern[i];
char c = current;
if (i < pattern.length() - 1) {
char next = pattern[i + 1];
if (next == '*') {
if (current == '.') {
c = ':';
} else {
c = (char) (current - 32);
}
i++;
}
}
newPattern.push_back(c);
}
for (int i = 0; i < str.length(); i++) {
vector<char> v;
v.reserve(newPattern.size());
for (int j = 0; j < newPattern.size(); ++j) {
v.push_back('u');
}
cache->push_back(v);
}
bool result = toNextMatch(str, newPattern, 0, 0);
return result;
}
bool toNextMatch(string &str, vector<char> &pattern, int str_pointer, int pat_pointer) {
if (str_pointer < str.length() && pat_pointer < pattern.size())
if (cache->at(str_pointer)[pat_pointer] != 'u') {
//cout<<str.substr(str_pointer,str.length()-1)<<" "<<pat_pointer<<" 直接返回結果"<<endl;
return cache->at(str_pointer)[pat_pointer] == 'y';
}
//cout<<"toNextMatch method called "<<str.length()<<" "<<str_pointer<<" "<<pattern.size()<<" "<<pat_pointer<<endl;
if (pat_pointer == pattern.size()) {
return str_pointer == str.length(); //檢查pattern 是否消耗完了,如果沒有消耗完,代表不匹配
}
char pattern_current = pattern[pat_pointer];
if (pattern_current == ':' || isBigger(pattern_current)) {
//複雜字符,可能匹配多個,也可能一個不匹配
bool zero_match = toNextMatch(str, pattern, str_pointer, pat_pointer + 1); //一個也沒有匹配
if (str_pointer < str.length() && pat_pointer + 1 < pattern.size())
cache->at(str_pointer)[pat_pointer + 1] = (zero_match ? 'y' : 'n');
if (zero_match) {
return true; //我一個也不匹配,後面的pattern 告訴我成功了,那我還能什麼,直接返回成功
} //如果失敗了,也不要氣餒,繼續匹配
int start = str_pointer;
while (start < str.length()) {
//cout<<"offset "<<(start-str_pointer+1)<<endl;
if (match(str[start], pattern_current)) { //匹配成功,並且打算就匹配到這個位置,後面的數據,嘗試讓後面的pattern 去匹配
int offset = str_pointer + start - str_pointer + 1;
bool unknown = toNextMatch(str, pattern, offset, pat_pointer + 1);
if (offset < str.length() && pat_pointer + 1 < pattern.size())
cache->at(offset)[pat_pointer + 1] = unknown ? 'y' : 'n';
if (unknown) {
//cout<<"return true"<<endl;
return true;
} //雖然失敗了,也不要氣餒,後面還有機會,堅持就是勝利
} else {
//儘可能地匹配都沒有一個可以成功的,最終也會失敗,等着從while 出去再返回false,因爲存在str匹配完了的問題
break;
}
start++;
}
return false; //毀滅吧,我累了
} else {
if (str_pointer >= str.length()) {
return false;
}
//普通字符,匹配一個,就結束
if (match(str[str_pointer], pattern_current)) {
//cout<<"next"<<endl;
return toNextMatch(str, pattern, str_pointer + 1, pat_pointer + 1); //匹配成功,繼續向下匹配
} else {
return false; //匹配失敗,不需要繼續進行下去了
}
}
}
static bool isBigger(char c) {
return c >= 'A' && c <= 'Z';
}
static bool match(char _s, char _p) {
//cout<<"match called "<<_s<<"-"<<_p<<endl;
if (isBigger(_p)) {
return _s - _p == 32;
} else if (_p == ':') {
return true;
} else if (_p == '.') {
return true;
} else {
return _s == _p;
}
}
~Solution(){
delete cache;//析構函數,否則會內存泄漏,AddressSanitizer挺好用
}
};
其他的解題思路
動態規劃,有限狀態機