Leetcode:Regular Expression Matching
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Leetcode:Regular Expression Matching相关的知识,希望对你有一定的参考价值。
题目大意是要求我们实现一个简单的正则表达式全匹配判断。其中正则表达式中只包含一般字符,以及全匹配字符.和变长字符*。其中.可以匹配一个字符,而*与前一个字符相关联,x*可以被看作任意多个x(0到正无穷个)。题目要求我们判断一个字符串是否与正则表达式完全匹配,比如‘.*‘完全匹配‘‘,但是‘a*‘不能完全匹配‘b‘。
这道题目可以用动态规划来解决。记s为待匹配的字符串,n为s的长度,p表示正则表达式字符串,m为p的长度。我们先对p进行一些预处理,将p转换为一般字符串(不包含.和*),但是其中每个字符都拥有两个布尔属性,分别是matchall (是否能匹配所有字符)和flexible (是否可以改变长度)。这可以通过类似下面的方式快速实现:
stk = empty-stack
for(i = 0; i < p.length; i++)
if(p[i] == ‘*‘)
stk.top.flexible = true
else
stk.push(p[i])
if(p[i] == ‘.‘)
stk.top.matchall = true
p = stk.inner-array
令dp[i][j]表示p[i...]与s[j...]是否完全匹配。dp[i][j]为真,当且仅当下述至少一个条件得到满足:
1.如果p[i].flexible是假,且p[i]能匹配s[j],且dp[i+1][j+1]为真。
2.如果p[i].flexible是真,且dp[i+1][j]为真。
3.如果p[i].flexible是真,且p[i]能匹配s[j],且dp[i][j+1]为真。
这三个条件的充分性非常容易验证,下面仅说明必要性。在dp[i][j]为真的情况下,若p[i]不可扩展,则显然p[i]与s[j]匹配,且p[i+1:m]与s[j+1:n]匹配,这与条件一符合。若p[i]可扩展,那么可以依据p[i]匹配0个字符和多个字符区分,匹配零个字符时,p[i+1:m]与s[j:n]匹配,匹配至少一个字符时有p[i:m]与s[j+1:n]匹配,而者分别落于条件2和条件3中。
利用以上的论述书写我们的代码:
getDp(i, j)
if(dp[i][j] has been initialized) //如果dp[i][j]已经被初始化过了
return dp[i][j]
//处理条件1
if(p[i].flexible == false)
dp[i][j] = (p[i].matchall || p[i] == s[j]) && getDp(i+1,j+1)
//处理条件2和3
else
flag = getDp(i + 1, j) || ((p[i].matchall || p[i] == s[j]) && getDp(i, j+1))
return dp[i][j]
而对于s与p是否最终完全匹配,只需要调用getDp(0, 0)即可得到结果。上述代码中没有处理越界的情况,可以在为dp分配空间时分配额外的边界空间,并在首次调用getDp之前对边界情况做判断。
上述代码的空间复杂度完全取决于dp的大小,故可以认为是O(mn),而由于每次对getDp(i,j)的调用,如果dp[i][j]以及被初始化过了,则费用为O(1),而完全初始化dp的费用为O(nm),因此可以认为getDp(0,0)的时间复杂度为O(mn)。
最后还是老规矩,给出实现代码:
1 package cn.dalt.leetcode; 2 3 /** 4 * Created by dalt on 2017/6/13. 5 */ 6 public class RegularExpressionMatching { 7 byte[][] matchStatuses; 8 String text; 9 int tlen; 10 char[] patternBuf; 11 int plen; 12 int[] patternExtra; 13 final int FLEXIBLE = 1 << 0; 14 final int MATCH_ALL = 1 << 1; 15 16 public boolean isMatch(String s, String p) { 17 18 19 //Precalculate all needed information 20 int starCount = 0; 21 for (int i = 0, iBound = p.length(); i < iBound; i++) { 22 if (p.charAt(i) == ‘*‘) { 23 starCount++; 24 } 25 } 26 text = s; 27 int validPatternLength = p.length() - starCount; 28 patternBuf = new char[validPatternLength]; 29 patternExtra = new int[validPatternLength]; 30 int wpos = 0; 31 for (int i = 0, iBound = p.length(); i < iBound; i++, wpos++) { 32 char ch = p.charAt(i); 33 if (ch == ‘*‘) { 34 wpos--; 35 patternExtra[wpos] |= FLEXIBLE; 36 } else if (ch == ‘.‘) { 37 patternExtra[wpos] |= MATCH_ALL; 38 } else { 39 patternBuf[wpos] = ch; 40 } 41 } 42 tlen = s.length() + 1; 43 plen = validPatternLength + 1; 44 matchStatuses = new byte[plen][tlen]; 45 matchStatuses[plen - 1][tlen - 1] = 1; 46 for (int i = 0, iBound = tlen - 1; i < iBound; i++) { 47 matchStatuses[validPatternLength][i] = -1; 48 } 49 for (int i = plen - 2; i >= 0; i--) { 50 matchStatuses[i][tlen - 1] = (byte) (matchStatuses[i + 1][tlen - 1] == 1 && (patternExtra[i] & FLEXIBLE) == FLEXIBLE ? 1 : -1); 51 } 52 return match(0, 0); 53 } 54 55 public boolean match(int i, int j) { 56 if (matchStatuses[i][j] != 0) { 57 return matchStatuses[i][j] == 1; 58 } 59 boolean flag; 60 if ((patternExtra[i] & FLEXIBLE) == 0) { 61 flag = ((patternExtra[i] & MATCH_ALL) == MATCH_ALL || patternBuf[i] == text.charAt(j)) && match(i + 1, j + 1); 62 } else { 63 boolean matchAllFlag = (patternExtra[i] & MATCH_ALL) == MATCH_ALL; 64 flag = match(i + 1, j); 65 if (!flag) { 66 flag = (matchAllFlag || patternBuf[i] == text.charAt(j)) && match(i, j + 1); 67 } 68 } 69 matchStatuses[i][j] = (byte)(flag ? 1 : -1); 70 return flag; 71 } 72 }
以上是关于Leetcode:Regular Expression Matching的主要内容,如果未能解决你的问题,请参考以下文章
[Leetcode] Regular expression matching 正则表达式匹配
[LeetCode] Regular Expression Matching
Leetcode:Regular Expression Matching
日常Exception第三十四回:mybatis-plus插入insert时null值导致报错,ExpressionSyntaxException: Malformed OGNL expressi