剑指 Offer 19 正则表达式匹配-动态规划

题目

请实现一个函数用来匹配包含’. ‘和’*‘的正则表达式。模式中的字符’.‘表示任意一个字符,而’*'表示它前面的字符可以出现任意次(含0次)。在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但与"aa.a"和"ab*a"均不匹配。

在这里插入图片描述
思路:从s[0:1]与p[0:1]是否匹配开始判断,然后每轮增加一个字母,可分为s增加一字母,判断是否匹配;p增加一位,判断是否匹配,直至判断s[0:m]与p[0:n]是否匹配。 (设s.length()=m, p.length()=n)
这样就有m*n种状态

动态规划

  • 状态定义:m*n维dp矩阵,dp[i][j]表示s前i个字母与p前j位匹配

  • 状态转移方程:为了在dp的下标与s,p下标对齐,先对s、p进行处理。s = " " + s, p = " " + p。这样s[i]就表示第i位字母

    当p[j] = '*'时:以下3种请况为true则为true
    1. dp[i][j-2] :p[j-1]* 取0次 如:s = a p = ab*,b*等于空
    2. dp[i-1][j] && s.charAt(i) == p.charAt(j-1):让p[j-1]* 取两次或取一次
    举例:s = aaa p = aa* (a*=aa) or s = aa p = aa*(a*=a)
    3.(dp[i-1][j] && p.charAt(j-1) == ‘.’):与2类似,不过把a变成了’.’,’.'可以匹配任意一个字符,让p[j-1]* 取两次或取一次 。
    举例:s = aaa p = a.*(.* = aa) or s = aa p = a.*(.* = a)

    当p[j] !=’*'时:
    普通字符或’.'的匹配,匹配时,除了配对s[i]==p[j]外,还应检查s[:i]能否与p[:j]配对。
    即检查dp[i-1][j-1]是否为true

    1. dp[i-1][j-1] && (s.charAt(i) == p.charAt(j):s[i]和p[j]为相同字母,且s前i-1个字母与p前j-1位匹配
    2. (dp[i-1][j-1] && p.charAt(j) == ‘.’):p[j]=’.'可以配对任意字母,且s前i-1个字母与p前j-1位匹配。
  • 初始状态:s和p的前面是空字符,两空字符匹配,dp[0][0]=1。
    初始化首行 ,当s = " ",只有当p的偶数位为*才可以匹配成功 如a*a*(也就相当于空)

  • 返回值:返回dp[m-1][n-1],即s与p是否匹配成功

class Solution{

	public boolean isMatch(String s,String p){
		int m = s.length() + 1, n = p.length() + 1;
		//使dp的下标与s,p下标对齐
		s = " " + s;
		p = " " + p;
		
		boolean[][] dp = new boolean[m][n];
		//s = " ",p=" ",空字符能匹配成功
		dp[0][0] = true;
		//初始化首行 s = " ",只有当p的偶数位为*才可以匹配成功 如a*a*
		for(int j = 2;j < n; j++){
			dp[0][j] = dp[0][j-2] && p.charAt(j) == '*';
		}

		//s前i个字符与p前j个字符是否能匹配上
		for(int i = 1; i < m; i++){
			for(int j = 1; j < n; j++){
				if(p.charAt(j) == '*'){
					//p[j-1]* 取0次   s = a  p = ab*
					if(dp[i][j-2])dp[i][j] = dp[i][j-2];
					//让p[j-1]* 取两次或取一次  s = aaa p = aa*/a.*   or s = aa   p = aa*/a.*
					else if(dp[i-1][j] && (s.charAt(i) == p.charAt(j-1) || p.charAt(j-1) == '.'))
						dp[i][j] = true;
				}
				else{
					//普通字符或'.'的匹配,匹配时,除了配对s[i]==p[j]外,还应检查s[:i]能否与p[:j]配对
					//即检查dp[i-1][j-1]是否为true
					//s[i]和p[j]为相同字母或p[j]='.'可以配对任意字母
					if(dp[i-1][j-1] && (s.charAt(i) == p.charAt(j) || p.charAt(j) == '.'))dp[i][j] = true;
				}
			}
		}
		return dp[m][n];
	}
}

题目来源:力扣(LeetCode)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值