剑指 Offer 19. 正则表达式匹配 (golang版)

  • 题目描述
请实现一个函数用来匹配包含'. ''*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(含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)
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值