leetcode之正则表达式匹配Golang
正则表达式这道题对我来说是真的难,花了两天的时间才做出来。
做这道题首先需要注意的是点号`.`可以匹配任何字符,字符加星号`*`表示零个或者多个该字符,例如a*表示零个或者多个a,所以对于正则表达式中,后面不跟*的字符,在字符串s中必须找到对应的字符,对于正则表达式中后面跟*的字符,则可以不必找到对应的字符,或者可以连续找到多个对应的字符。
题目中给了5个用例:
例如用例4:正则表达式p中c*可以表示0个c,a*表示2个a,b因为不跟*,所以必须表示一个b,这样就刚好是aab,和原字符串匹配了
例如用例5:正则表达式p中mi已经成功匹配,然后s*表示2个s,然后i也匹配了,然后s*也表示2个s,然而,p中紧跟s*的是p*,而原字符串中是ssipp,所以中间有一个i没有匹配上,从而就匹配失败,所以会返回false
知道了匹配的规则,那么我们如何匹配呢?
最开始我尝试了贪心算法,也就是前面不跟星号的字符就匹配一个,然后跟星号的字符就尽可能匹配多的字符,然后这种方法我失败了,没做出来,越想越复杂。。。。
然后使用动态规划算法:
首先我们需要对正则表达式进行处理,例如用例5中的正则表达式可以转化成如下形式:
mis*is*p*.
我们第一步就是处理星号,将星号变成它前面字符的标志位,如果带星号,那么标志位为true,否则标志位为false,设新的带标志位的正则表达式为np(newP),所以np有两个字段np.value和np.flag
动态规划的每一个子问题就是原字符串中当前位置的字符,和正则表达式中当前的规则是否匹配:s[i]?=np[j] || np[j]?=‘.‘(也就是字符是否相等,或者正则表达式中的规则是否为点号)
然后就是定义状态。假设State(i,j)表示字符串np[i]和正则表达式s[j]之前的数据都已经匹配成功了
那么状态转移方程是怎样的呢?我们通过一个图来看:
此时我们需要计算State(i,j),那么在他之前的三个状态我们肯定都是已经计算出来了的,所以已知三个状态State(i-1,j-1),State(i-1,j),State(i,j-1),所以我们需要用这三个状态来确定状态转移方程从而确定State(i,j):
1、State(i-1,j-1)==true && (np[i].value==s[j] || np[i].value==‘.‘) ==>State(i,j)=true
此时是np的长度和s的长度是一样的
2、State(i-1,j)==true && np[i-1].flag==true ==> State(i,j)=true
此时np更长,所以np比s长的部分必须是带星号的字符才能匹配,因为这样才能让np更长的部分表示0个字符
3、State(i,j-1)==true && np[i-1].flag==true && ( np[i-1].value==s[j] || np[i-1]==‘.‘) ==> State(i,j)=true
此时s更长,那么np最后一个字符必须是带星号的字符,因为这样才能扩充他的长度,并且还要满足字符相同或者为点号才能匹配上
当整个状态被我们存进二维数组以后,输出最后的状态即可
代码如下:
func isMatch(s string, p string) bool { type node struct { name byte flag bool } tmpStr := strings.ReplaceAll(p, "*", "") npLength := len(tmpStr) sLength := len(s) np := make([]node, npLength) pLength := len(p) nIndex, pProcessIndex := 0, 0 for pProcessIndex != pLength { if p[pProcessIndex] == ‘*‘ { np[nIndex-1].flag = true pProcessIndex++ continue } np[nIndex].name = p[pProcessIndex] nIndex++ pProcessIndex++ } // fmt.Printf("%v\n", np) result := make([][]bool, npLength+1) for i := 0; i <= npLength; i++ { result[i] = make([]bool, sLength+1) } // fmt.Printf("%v\n", result) for i := 0; i <= npLength; i++ { for j := 0; j <= sLength; j++ { if i == 0 && j == 0 { result[i][j] = true } if i == 0 && j != 0 { result[i][j] = false } if i != 0 { if result[i-1][j] && np[i-1].flag { result[i][j] = true } if j != 0 { if result[i][j-1] && np[i-1].flag && (np[i-1].name == s[j-1] || np[i-1].name == ‘.‘) { result[i][j] = true } if result[i-1][j-1] && (np[i-1].name == ‘.‘ || np[i-1].name == s[j-1]) { result[i][j] = true } } } } } // fmt.Printf("%v\n", result) return result[npLength][sLength] }