力扣第十题题解
思路
问题描述就不写了,直接放地址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挺好用
}
};
其他的解题思路
动态规划,有限状态机