- 题目描述
请实现一个函数用来匹配包含'. '和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(含0次)。在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但与"aa.a"和"ab*a"均不匹配。
示例 1:
输入:
s = "aa"
p = "a"
输出: false
解释: "a" 无法匹配 "aa" 整个字符串。
示例 2:
输入:
s = "aa"
p = "a*"
输出: true
解释: 因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。
示例 3:
输入:
s = "ab"
p = ".*"
输出: true
解释: ".*" 表示可匹配零个或多个('*')任意字符('.')。
示例 4:
输入:
s = "aab"
p = "c*a*b"
输出: true
解释: 因为 '*' 表示零个或多个,这里 'c' 为 0 个, 'a' 被重复一次。因此可以匹配字符串 "aab"。
示例 5:
输入:
s = "mississippi"
p = "mis*is*p*."
输出: false
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母以及字符 . 和 *,无连续的 '*'。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zheng-ze-biao-da-shi-pi-pei-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
-
思路:
1、不能考虑太复杂,否则会陷入死胡同中,总会有一些情况考虑不到
2、极端情况跟下,字符串s和匹配模式p,p为".*"可以匹配所有字串,s和p都为空也是匹配,s为空但p不为空,不可能匹配
3、一般情况,“*”代表前面的字符串出现1次活多次,需要考虑到每一种情况并去验证,即出现0次,则p的下标直接+2跳过,出现1次,出现多次
4、递归解决逻辑会清晰一些,注意要保存每次匹配的结果避免递归效率低下,不然会报超时,注意边界 -
代码
func isMatch(s string, p string) bool {
//临时切片,保存递归时当前步骤的结果,默认值0,1代表匹配,2匹配失败
tmp := make([][]int,len(s)+1)
for i := range tmp {
tmp[i] = make([]int,len(p)+1)
}
//匹配模式p为".*"可以匹配所有字符,直接返回true
//s和p都为空字符串,直接返回true
if p == ".*" || (len(s) == 0 && len(p) == 0) {
return true
}
//s为空,p不为空,直接返回false
if len(s)>0 && len(p)==0 {
return false
}
return match(s,p,len(s),len(p),0,0,tmp)
}
func match(s string, p string,lenS int, lenP int, i int, j int,tmp [][]int) bool {
//值为2代表之前已有步骤判断过该位置处不匹配,直接返回结果
if tmp[i][j] == 2 {
return false
}
//字符串匹配,返回true
if i == lenS && j == lenP {
tmp[i][j] = 1
return true
}
/* 当下一个字符为“*”时,有三种状况
* 1: "*"前的字符匹配0次,j跳过该字符及“*”字符,j=j+2
* 2: "*"前的字符匹配1次,比对s[i]和p[j]的值后向前移动
* 3: "*"前字符串匹配多次
*/
if j<lenP-1 && string(p[j+1])=="*" {
if match(s,p,lenS,lenP,i,j+2,tmp) || (i<lenS && (string(s[i])==string(p[j]) || string(p[j])==".") && match(s,p,lenS,lenP,i+1,j+2,tmp)) || (i<lenS && (string(s[i])==string(p[j]) || string(p[j])==".") && match(s,p,lenS,lenP,i+1,j,tmp)){
tmp[i][j] = 1
return true
}else{
tmp[i][j] = 2
return false
}
}else if i<lenS && j<lenP && (string(s[i])==string(p[j]) || string(p[j])==".") {
if match(s,p,lenS,lenP,i+1,j+1,tmp) {
tmp[i][j] = 1
return true
}else{
tmp[i][j] = 2
return false
}
}
return false
}
- 完整版测试代码
package main
import (
"fmt"
)
func main() {
test()
}
func isMatch(s string, p string) bool {
//临时切片,保存递归时当前步骤的结果,默认值0,1代表匹配,2匹配失败
tmp := make([][]int,len(s)+1)
for i := range tmp {
tmp[i] = make([]int,len(p)+1)
}
//匹配模式p为".*"可以匹配所有字符,直接返回true
//s和p都为空字符串,直接返回true
if p == ".*" || (len(s) == 0 && len(p) == 0) {
return true
}
//s为空,p不为空,直接返回false
if len(s)>0 && len(p)==0 {
return false
}
return match(s,p,len(s),len(p),0,0,tmp)
}
func match(s string, p string,lenS int, lenP int, i int, j int,tmp [][]int) bool {
//值为2代表之前已有步骤判断过该位置处不匹配,直接返回结果
if tmp[i][j] == 2 {
return false
}
//字符串匹配,返回true
if i == lenS && j == lenP {
return true
}
/* 当下一个字符为“*”时,有三种状况
* 1: "*"前的字符匹配0次,j跳过该字符及“*”字符,j=j+2
* 2: "*"前的字符匹配1次,比对s[i]和p[j]的值后向前移动
* 3: "*"前字符串匹配多次
*/
if j<lenP-1 && string(p[j+1])=="*" {
if match(s,p,lenS,lenP,i,j+2,tmp) || (i<lenS && (string(s[i])==string(p[j]) || string(p[j])==".") && match(s,p,lenS,lenP,i+1,j+2,tmp)) || (i<lenS && (string(s[i])==string(p[j]) || string(p[j])==".") && match(s,p,lenS,lenP,i+1,j,tmp)){
tmp[i][j] = 1
return true
}else{
tmp[i][j] = 2
return false
}
}else if i<lenS && j<lenP && (string(s[i])==string(p[j]) || string(p[j])==".") {
if match(s,p,lenS,lenP,i+1,j+1,tmp) {
tmp[i][j] = 1
return true
}else{
tmp[i][j] = 2
return false
}
}
return false
}
func test(){
s := "aa"
p := "a"
if isMatch(s,p) != false {
println("N",s,p)
}
s = "aa"
p = "a*"
if isMatch(s,p) != true {
println("N",s,p)
}
s = "ab"
p = ".*"
if isMatch(s,p) != true {
println("N",s,p)
}
s = "aab"
p = "c*a*b"
if isMatch(s,p) != true {
println("N",s,p)
}
s = "mississippi"
p = "mis*is*p*."
if isMatch(s,p) != false {
println("N",s,p)
}
s = "aa"
p = "aaa"
if isMatch(s,p) != false {
println("N",s,p)
}
s = "aaa"
p = "a*"
if isMatch(s,p) != true {
println("N",s,p)
}
s = "aaa"
p = "a*a"
if isMatch(s,p) != true {
println("N",s,p)
}
s = "aaa"
p = "ab*a*c*a"
if isMatch(s,p) != true {
println("N",s,p)
}
s = "a"
p = "ab*a"
if isMatch(s,p) != false {
println("N",s,p)
}
s = "a"
p = "ab*"
if isMatch(s,p) != true {
println("N",s,p)
}
s = "bbbba"
p = ".*a*a"
if isMatch(s,p) != true {
fmt.Println("N",s,p)
}
s = ""
p = "c*"
if isMatch(s,p) != true {
println("N",s,p)
}
s = "aaaaaaaaaaaaab"
p = "a*a*a*a*a*a*a*a*a*a*c"
if isMatch(s,p) != false {
println("N",s,p)
}
}