leetcode之正则表达式匹配Golang

码墨 2020-06-16

正则表达式这道题对我来说是真的难,花了两天的时间才做出来。

做这道题首先需要注意的是点号`.`可以匹配任何字符,字符加星号`*`表示零个或者多个该字符,例如a*表示零个或者多个a,所以对于正则表达式中,后面不跟*的字符,在字符串s中必须找到对应的字符,对于正则表达式中后面跟*的字符,则可以不必找到对应的字符,或者可以连续找到多个对应的字符。

题目中给了5个用例:

leetcode之正则表达式匹配Golang

 例如用例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*.

leetcode之正则表达式匹配Golang

   我们第一步就是处理星号,将星号变成它前面字符的标志位,如果带星号,那么标志位为true,否则标志位为false,设新的带标志位的正则表达式为np(newP),所以np有两个字段np.value和np.flag

动态规划的每一个子问题就是原字符串中当前位置的字符,和正则表达式中当前的规则是否匹配:s[i]?=np[j] || np[j]?=‘.‘(也就是字符是否相等,或者正则表达式中的规则是否为点号)

然后就是定义状态。假设State(i,j)表示字符串np[i]和正则表达式s[j]之前的数据都已经匹配成功了

那么状态转移方程是怎样的呢?我们通过一个图来看:

leetcode之正则表达式匹配Golang

   此时我们需要计算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)=trueleetcode之正则表达式匹配Golang

    此时是np的长度和s的长度是一样的

  2、State(i-1,j)==true && np[i-1].flag==true  ==> State(i,j)=trueleetcode之正则表达式匹配Golang

    此时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)=trueleetcode之正则表达式匹配Golang

       此时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]
}

相关推荐