Leetcode OJ: Regular Expression Matching
来源:互联网 发布:熊片数据库手机版 编辑:程序博客网 时间:2024/06/05 09:19
Regular Expression Matching
Implement regular expression matching with support for '.'
and '*'
.
'.' 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") → falseisMatch("aa","aa") → trueisMatch("aaa","aa") → falseisMatch("aa", "a*") → trueisMatch("aa", ".*") → trueisMatch("ab", ".*") → trueisMatch("aab", "c*a*b") → true
实现个简单的正则匹配,支持'.'与'*'的操作
解决这题的关键是思路要清晰,考虑要周全。
1. 递归实现。
思路:
isMatch(s, p):
1. 当前p为0时,若s也是0时,则返回true,否则为false
2. 当前p不为0时,
1) p的下一个不是'*'时
if: 当前s与p匹配,
则表明到此都是匹配的,只需要检查isMatch(s + 1, p + 1)
else:
返回false
2) p的下一个是'*'时,
while: 当前s与p匹配,即表明至此也是匹配的
if: 当前s与下一个p也都匹配,即isMatch(s, p + 2),则返回true
else: s++
此时,当前s与当前p已经不匹配了(之前s都是匹配的),则检测下一个模板isMatch(s, p + 2)
代码如下:
1 class Solution { 2 public: 3 bool isMatch(const char *s, const char *p) { 4 if (*p == '\0') return *s == '\0'; 5 if (*(p+1) != '*') { 6 return ((*p == *s) || (*p == '.' && *s != '\0')) && isMatch(s+1, p+1); 7 } 8 while ((*p == *s) || (*p == '.' && *s != '\0')) { 9 if (isMatch(s, p+2)) return true;10 s++;11 }12 return isMatch(s, p+2);13 }14 };
最终是116ms过了
2. 动态规划实现
其实根据以上思路,就很容易就有动态规划的思路了,小小的trick就是假设s与p的开头都加了一个空字符,方便统一规则。
DP(i, j)存的是p[0:i-1]与s[0:j-1]的匹配情况。
且看下面的图与说明
DP(i+1, j+1)是要更新的状态,对应p[i]和s[j]
1. 当p[i] 的下一个不为'*'时,此时只跟上一个状态的p与上一个s对应的DP(i, j)有关
因为此时匹配的条件是:A. p[i]与s[j]匹配。B. p[0:i-1]与s[0:j-1]完全匹配,即DP(i, j)==true。
则有
DP(i+1, j+1) = DP(i, j) && Match(p[i], s[j])
另外考虑DP(i+1, 0),这个值对应的是s[-1]与p[i],s[-1]即假设存在的空字符,明显p[i]与s[-1]是不匹配的
因此这时的DP(i+1, 0) = false
而要让规划顺利地开始,(特别是当第一个匹配对的就是这种情况时)就需要让DP(0, 0)=true了。
2. 当p[i]的下一个为'*'时,此时就与围绕这一状态的都有关。
1) 如果DP(i, j+1)是true时,即上一个pattern就已经完全匹配了当前的s,那当前状态也应该是true,即DP(i+1, j+1)=true
2) 否则,DP(i, j)与DP(i+1, j)其中有一个为true, 而且p[i]与s[j]匹配,则DP(i+1, j+1)为true,即
DP(i+1, j+1) = (DP(i, j) || DP(i+1, j)) && Match(p[i], s[j])
此时考虑DP(i+1, 0)则需要DP(i, 0)的配合,DP(i+1, 0) = DP(i, 0) && Match(p[i], s[-1])
而Match(p[i], s[-1])永远为真,所以DP(i+1, 0) = DP(i, 0)
另外考虑到匹配情况只跟相邻两层有关,所以实现时就只用了两层存状态。代码如下
1 class Solution { 2 public: 3 bool isMatchSingle(char s, char p) { 4 return p == s || p == '.'; 5 } 6 7 bool isMatch(const char *s, const char *p) { 8 int slen = strlen(s); 9 int plen = strlen(p);10 // 用于存当前层匹配结果与上一层匹配结果11 vector<bool> dp1(slen + 1, false), dp2(slen + 1, false);12 vector<bool> *pre = &dp1, *cur = &dp2;13 14 // 第一个为true,因为默认地给s与p的开始都添加了个空字符15 dp1[0] = true;16 const char* pp = p;17 while (pp[0] != 0) {18 // 指向当前层匹配结果与上一层匹配结果的引用19 vector<bool>& curr = *cur;20 vector<bool>& prer = *pre;21 22 // 初始化23 curr.assign(slen + 1, false);24 if (pp[1] != '*') {25 // curr[0]都将为false26 for (int i = 0; i < slen; ++i) {27 curr[i + 1] = (prer[i] && isMatchSingle(s[i], pp[0]));28 }29 pp += 1;30 } else {31 // curr[0]只与prer[0]相关32 curr[0] = prer[0];33 for (int i = 0; i < slen; ++i) {34 curr[i + 1] = (prer[i + 1] || (isMatchSingle(s[i], pp[0]) && (prer[i] || curr[i])));35 }36 pp += 2;37 }38 // 交换,注意是指针的交换,没有换数据39 swap(cur, pre);40 }41 return (*pre)[slen];42 }43 };
最终52ms过了。
个人也加了些优化,给每一层都加个计数器,当是没有*的情况下,上一层为True的节点已经到结尾了,26行的循环就可以跳出了。
实现了一记,24ms过了,有兴趣的同学可以试试看。
- LeetCode OJ:Regular Expression Matching
- LeetCode OJ - Regular Expression Matching
- Leetcode OJ: Regular Expression Matching
- LeetCode OJ Regular Expression Matching
- LeetCode OJ --- Regular Expression Matching
- leetCode OJ 10. Regular Expression Matching
- LeetCode: Regular Expression Matching
- LeetCode: Regular Expression Matching
- leetcode Regular Expression Matching
- [Leetcode] Regular Expression Matching
- [LeetCode]Regular Expression Matching
- LeetCode-Regular Expression Matching
- Regular Expression Matching LeetCode
- LeetCode | Regular Expression Matching
- LeetCode: Regular Expression Matching
- Leetcode: Regular Expression Matching
- [LeetCode] Regular Expression matching
- [LeetCode] Regular Expression Matching
- SSH Secure Shell Client登陆配置服务器mysql命令
- Convert jQuery RGB output to Hex Color
- ECharts案例教程1
- Object V.S datastructure
- linux命令大全
- Leetcode OJ: Regular Expression Matching
- leetcode Question 123: Wildcard Matching
- 堆结构(二) - 左倾堆的原理与实现
- coding是工程师的基本修养
- 记录平时code点滴,这次是通过一张充满异样字符的表,对数据表中的每一列进行清理,比double quotation的issue难多了!
- 在编程竞赛中提高实战的技能
- http和https的区别
- 权限管理设计(一)
- 权限管理设计(二)