经过上周的medium热身之后,这周决定选个hard的来训练一下。 这次题目为正则表达式,描述如下。原题链接
‘.’ Matches any single character. ‘*’ Matches zero or more of the PReceding element.
The matching should cover the entire input string (not partial).
The function prototype should be: bool isMatch(const char *s, const char *p)
Some examples: isMatch(“aa”,”a”) → false isMatch(“aa”,”aa”) → true isMatch(“aaa”,”aa”) → false isMatch(“aa”, “a*”) → true isMatch(“aa”, “.*”) → true isMatch(“ab”, “.*”) → true isMatch(“aab”, “c*a*b”) → true
在以前学习CS的时候,老师最爱说的一句话是,当一个问题来临的时候,先去尝试最粗暴直接去解决它,如果这个直接方法效率太差,再去想办法去优化,解决问题先放在第一位。 于是,我使用了穷尽的方法……
不难看出来,正则表达式每一次匹配最多会有三种情况: Type 1.正则表达式向后偏移 (例子:a* 比配 b,此时之后正则表达式向后一位) Type 2.字符串向后偏移(例子:a*匹配 a,此时字符串匹配成功,向后一位,正则表达式可不便宜) Type 3.正则表达式和字符串都向后偏移(a匹配a,成功匹配,二者都向后偏移)
那么每一次匹配都是一颗三叉树,只要把这三叉树遍历完全,就会有答案。
结点的操作为: 1.当正则表达式和字符串都匹配到最尽头,返回成功。 2.如果能够按照上述三个条件生成出子节点的,加入子节点,然后遍历子节点。 3.如果既不成功,也不能生成子节点的,就返回失败。
既然是一棵树,那么就很明了了,直接上递归。 递归伪代码:
match(s, p, current_index_s, current_index_p): return1=return2=return3=false if s and p both end: return true; else: if Type1: return1 = match(s,p,cur_index_s, current_index_p+1) if Type2: return2 = match(s,p,cur_index_s+1, current_index_p) if Type3: return3 = match(s,p,cur_index_s +1, current_index_p+1) return return1 | return2 | return3跑出来结果,是对的,只是额……超时了。 上诉递归是有问题的,看起来像是深度优先,但是跑起来是完全遍历。 应该是这样才对。
match(s, p, current_index_s, current_index_p): return1=return2=return3=false if s and p both end: return true; else: if Type1: return1 = match(s,p,cur_index_s, current_index_p+1) if return1: return true if Type2: return2 = match(s,p,cur_index_s+1, current_index_p) if return2: return true if Type3: return3 = match(s,p,cur_index_s +1, current_index_p+1) if return3: return true return false再次提交,还是超时,超时的例子在于 a*a*a*a*a*a*c 和 ab的匹配,这个是匹配不成功的的样例,因此,无论是深度优先还是广度优先,都需要把树完全遍历一遍,这样显然是很慢的。
不过我选择的并不是再在递归上去做优化,而是对正则表达式做优化。 因为 a*a*a*a*a*a*c = a*c 同类的,还有: .a*b*c*d=.* a*a*aaaaaa*= a*aaaa
好了,做完优化后,提交成功了,中规中矩。
最后附上C++代码
# include <iostream># include <string>using namespace std;// 化简正则表达式string str_init(string p) { if (p.length() < 3) { return p; } string ret_str = string(); ret_str.push_back(p[0]); ret_str.push_back(p[1]); int index = 2; bool cfind = false; while (p[index] != '/0') { if (index + 1 < p.length() && p[index + 1] == '*') { int counter = index - 1; cfind = false; while (counter >= 0) { if (p[counter] != '*' && p[counter] != p[index]) { break; } if ((p[counter] == '.' || p[counter] == p[index]) && p[counter + 1] == '*') { cfind = true; break; } counter -= 1; } if (!cfind) { ret_str.push_back(p[index]); ret_str.push_back(p[index + 1]); index += 2; } else { index+=2; } } else { ret_str.push_back(p[index]); index++; } } return ret_str;}// 递归函数bool matchOne(string& s, string& p, int s_i, int p_i) { if (s[s_i] == '/0' && p[p_i] == '/0') { return true; } // Judgement bool type1 = false; bool type2 = false; bool type3 = false; if (s[s_i] == '/0') { if (p[p_i] == '*') { type1 = true; } } else { if (p[p_i] == '*') { type1 = true; if (s[s_i] == p[p_i - 1] || p[p_i - 1] == '.') { type2 = true; type3 = true; } } else { if (s[s_i] == p[p_i] || p[p_i] == '.') { type3 = true; } } } // Alignment bool ret1 = false; bool ret2 = false; bool ret3 = false; int temp_p_i = 0; int temp_s_i = 0; if (type3) { if (p_i + 2 < p.length() && p[p_i + 2] == '*') { temp_p_i = p_i + 2; } else { temp_p_i = p_i + 1; } temp_s_i = s_i + 1; ret3 = matchOne(s, p, temp_s_i, temp_p_i); if (ret3) { return true; } } if (type1) { if (p_i + 2 < p.length() && p[p_i + 2] == '*') { temp_p_i = p_i + 2; } else { temp_p_i = p_i + 1; } temp_s_i = s_i; ret1 = matchOne(s, p, temp_s_i, temp_p_i); if (ret1) { return true; } } if (type2) { temp_s_i = s_i + 1; temp_p_i = p_i; ret2 = matchOne(s, p, temp_s_i, temp_p_i); if (ret2) { return true; } } return false;}class Solution {public: bool isMatch(string s, string p) { int s_i = 0; int p_i = 0; string modified_p = str_init(p); if (p_i + 1 < p.length() && p[p_i + 1] == '*') { p_i++; } return matchOne(s, modified_p, s_i, p_i); }};新闻热点
疑难解答