leetcode 10. Regular Expression Matching
字符串匹配问题;
1、用暴力的方法解决。
通过搜索的方式,将每一种可能都列出来;
a*或.*的时候,分三路:1、s中没有匹配到,p直接右移两位继续递归搜索;2、s中有匹配到一个a,s右移一位,p右移两位继续递归搜索;3、s中有匹配到一个,p继续用a*继续匹配s接下去的字符,则s右移一位,p不右移继续递归搜索。
只有a或者.的时候,s和p有匹配到,两个都右移一位递归搜索;
bool Match(const string& s, int s_i, const string& p, int p_i) { while (p.length() < p_i && p[p_i] == '*') ++p_i; if (s.length() == s_i && p.length() == p_i) return true; else if (s.length() != s_i && p.length() == p_i) return false; if (p_i + 1 < p.length()) { if (p[p_i+1] == '*') { if (Match(s, s_i, p, p_i + 2)) return true; if (s.length() > s_i && (s[s_i] == p[p_i] || p[p_i] == '.')) { if (Match(s, s_i+1, p, p_i + 2)) return true; if (Match(s, s_i+1, p, p_i)) return true; } } else { if (s.length() > s_i && (s[s_i] == p[p_i] || p[p_i] == '.')) { if (Match(s, s_i+1, p, p_i + 1)) return true; } } } else { if (s.length() > s_i && (s[s_i] == p[p_i] || p[p_i] == '.')) { if (Match(s, s_i+1, p, p_i + 1)) return true; } } return false; }
通过搜索发现,当前的搜索结果跟之前字符的搜索结果是有关系的;
当p+1 == a*的时候;即可以匹配0~n个相同的数;所以当匹配0个的时候: f(s+1,p) = f(s,p); 当匹配n=1个的时候: f(s+1,p + 1) = f(s,p) 又因为a*也符合f(s+1,p+1) = f(s+1,p); 当匹配n>1个的时候,则f(s,p+1)是匹配的,那么也应该符合f(s+1,p+1) = f(s,p+1),假设aa 跟a*应该是匹配的;
所以f(s+1,p+1) = f(s+1, p) | f(s,p) | f(s,p+1)
当p+1 == a的时候,则只有 f(s+1,p+1) = f(s,p)
bool DP(const string& s, const string& p) { vector<bool> arr(s.length()+1, false); arr[0] = true; int p_i = 0; while (p_i < p.length()) { while (p_i < p.length() && p[p_i] == '*') ++p_i; if (p_i == p.length()) break; if (p_i + 1 < p.length()) { if (p[p_i+1] == '*') { bool cur = arr[0]; bool mid = cur; for (int i = 0; i < s.length(); ++i) { mid = cur; cur = arr[i+1]; if (p[p_i] == s[i] || p[p_i] == '.') { arr[i + 1] = mid | arr[i] | arr[i+1]; } } ++p_i; } else { bool cur = arr[0]; for (int i = 0; i < s.length(); ++i) { if (p[p_i] == s[i] || p[p_i] == '.') { bool mid = cur; cur = arr[i+1]; arr[i+1] = mid; } else { cur = arr[i+1]; arr[i+1] = false; } } arr[0] = false; } } else { bool cur = arr[0]; for (int i = 0; i < s.length(); ++i) { if (p[p_i] == s[i] || p[p_i] == '.') { bool mid = cur; cur = arr[i+1]; arr[i+1] = mid; } else { cur = arr[i+1]; arr[i+1] = false; } } arr[0] = false; } ++p_i; // for (int i = 0; i < arr.size(); ++i) // cout << arr[i] << " "; // cout << endl; } return arr[s.length()]; }
在代码中看到有一个可以操作的比较巧妙的地方:
原本的 bool cur = arr[0]; for (int i = 0; i < s.length(); ++i) { if (p[p_i] == s[i] || p[p_i] == '.') { bool mid = cur; cur = arr[i+1]; arr[i+1] = mid; } else { cur = arr[i+1]; arr[i+1] = false; } } 改进后的 for (int i = s.length() - 1; i >= 0; --i) { if (p[p_i] == s[i] || p[p_i] == '.') { arr[i+1] = arr[i]; } else { arr[i+1] = false; } }
通过逆序的方式可以不需要记住原先的值;
浙公网安备 33010602011771号