首先吐槽下,太恶心 了......一开始以为很简单,后来发现细节太多了......一直修修改改限制条件花了6个小时
先敲下黑板:直接暴力模拟的匹配模式
思路: 首先对于两个序列都要加上游标 sp , pp 从起点0开始
如果二者相等不断下行,sp++,pp++ 【直至不相等或者越界时出来 】
未越界只是不等的时候,首先要区分下面3种不等的情形
(1) s中字母与【' . '】不等,直接sp++,pp++
(2) s中字母与【' * '】不等 。(此时要考虑一下3种情况)
a. 是否是利用 * 来达到删除效果 ,如【 a , c* a】故删除 【c* 】利用递归判断【a , a】
b. 是否是只复制1次,如【abc, a*b*c*】,故也要递归本身来判断
c. 是否是复制N次,直至不相等处,且每复制比对一次都需要调用自身的递归函数来判断
(3) s中的字母与p中的字母不相等,此时要查看下p字母后面是否是*,是*可以删除当前字母还有救
如: ab,ac*b (不等时候,sp指向b,pp指向c)
只需要将 pp+2 (pp指向b) 继续判断就行了
越界时候,有以下3种情况
(1)sp和pp同时越界,说明匹配至最后,说明字符串是匹配的
(2)pp越界 sp没越界,一定不匹配
(3)sp越界,但是pp没越界。此时比较复杂,需要考虑一下2种情况
a. pp当前位置的字符是 * ,要判断 pp+1 至结尾能否抵消如 *a*b*c*d* 要判断a*b*c*d*这种
若能抵消则说明匹配
若不能抵消能否通过消除一个后进行匹配,如 abc,c*abc ,消除c*
消除能匹配就能匹配,消除不能匹配则s,p不能匹配
b. pp当前位置的字符不是*,是字母,则要判断pp至结尾的字符串能否抵消 如a*b*c*d* 这种
若能抵消则说明匹配
若不能抵消能否通过消除一个后进行匹配,如 abc,c*abc ,消除c*
消除能匹配就能匹配,消除不能匹配则s,p不能匹配
#include<iostream>
#include<vector>
#include<string>
using namespace std;
/*
*
'.' 匹配任意单个字符
'*' 匹配零个或多个前面的那一个元素
".*" 表示可匹配零个或多个('*')任意字符('.')。
*/
bool clearOne(string p) {//空串返回false
int p_len = p.length();
int pp = 0;
if (p.empty() || p == "")return false;
if (((pp + 1) < p.length()) && (p.at(pp + 1) == '*')) return true;
return false;
}
bool check_pnull(string p) {//判断规则p剩余部分是否可以抵消
int p_len = p.length();
int pp = 0;
if (p.empty() || p == "")return true;
while (pp < p_len) {//字母在
if (pp + 1 < p_len) {//*号在
if (p.at(pp + 1) == '*')//*匹配
pp += 2;
else
return false;
}
else {//*号不在
if (p.at(pp) == '*')
return true;
return false;
}
}
return true;
}
bool isMatch(string s, string p) {
int s_len = s.length();
int p_len = p.length();//二者长度
int sp, pp;//哨兵
sp = pp = 0;//初始化
if ((!s.empty()) && (p.empty() || p == ""))return false;
if (!p.empty() && (s.empty() || s == "")) {
if (check_pnull(p))return true;
return false;
}//去除非法情况和特殊空串情况
while (sp < s_len || pp < p_len) {
while ((sp < s_len && pp < p_len) && s.at(sp) == p.at(pp)) {//二者相等就顺着排
sp++; pp++;
}//匹配就下行
//出来有可能是不匹配也有可能是超过长度
//1不匹配
if (sp < s_len && pp < p_len) {//确保在长度内
if (p.at(pp) == '.') {//.类型不匹配
sp++; pp++;
}
else if (p.at(pp) == '*') {//*类型不匹配
bool real = false;
int temp_sp = sp - 1;
//第一种先消去*前面的来跟s匹配
if (pp + 1 < p_len)//未越界情况才有可能消去,越界一定不用消除
real= isMatch(s.substr(temp_sp, s_len - temp_sp), p.substr(pp + 1, p_len - pp - 1));
if (real)return true;
//第二种到底匹配几个的问题
if ((sp < s_len && pp + 1 < p_len)) {//*只匹配一次
real = isMatch(s.substr(sp, s_len - sp), p.substr(pp + 1, p_len - pp - 1));
if (real)return true;
}
while ((sp < s_len && pp < p_len)) {//从第2此开始依次匹配
if ((s.at(sp) == p.at(pp - 1)) || p.at(pp - 1) == '.') {
sp++;
if ((sp < s_len && pp + 1 < p_len)) {
real = isMatch(s.substr(sp, s_len - sp), p.substr(pp + 1, p_len - pp - 1));
if (real)return true;
}
}
else {
pp++;
break;
}
}
// pp++;
}
else {
if ((pp + 1 < p_len) && (p.at(pp + 1) == '*')) {//还有救
pp += 2;
}
else
return false;
}
}
else {//2超出长度
//如果二者同时超出了长度则说明匹配成功
//若是单独一方超出则要看情况
//a. 若p超出了长度,说明s串还有未比配的数,一定不匹配
//b. 若s超出了长度,说明要回溯,两种检查,剩下p是否能check_pnull,若能则匹配,若不能则claenOne弄掉一对让s的最后一个字母与剩下的p规则匹配
if (sp == s_len && pp == p_len) {//二者同时超出了长度则说明匹配成功
return true;
}
else {//单独一方超出
if (pp >= p_len)return false;//a
if (sp >= s_len) {//b
if (p.at(pp) == '*') {//最后超出的p中,pp所在的位置是*
if (check_pnull(p.substr(pp + 1, p_len - pp))) return true;//剩下的能消除//*从pp + 1开始
else {//不能消除
if (clearOne(p.substr(pp - 1, p_len - pp + 1))) {
sp--;
pp = pp + 1;
return isMatch(s.substr(sp, s_len - sp), p.substr(pp, p_len - pp));
}
else return false;
}
}
else {//最后超出的p中,pp所在位置不是*
if (check_pnull(p.substr(pp, p_len - pp))) return true;//剩下的能消除//不是*从pp开始
else {//不能消除
if (clearOne(p.substr(pp - 1, p_len - pp + 1))) {
sp--;
pp = pp + 1;
return isMatch(s.substr(sp, s_len - sp), p.substr(pp, p_len - pp));
}
else return false;
}
}
}
}
}
}
if (sp == s_len && pp == p_len)
return true;
else
return false;
}
int main(void) {
cout << isMatch("bcbacacbacbbbbcac", "..*a*a*b*c*.*a*bb*.") << endl;
return 0;
}