动态规划-正则表达式匹配(10)(保留有一个问题)

题目: 在这里插入图片描述
示例:
1.

输入:
s = “aa”;
p = “a”;
输出:false;
解释:"a"无法匹配"aa"整个字符串

输入:
s = “aa”
p = “a*”
输出:true
解释:因为"* "可以匹配零个或多个前一个元素,故"a* “可以匹配"aa”

输入:
s = “ab”
p = ".* ”
输出: true
解释: ".* " 表示可匹配零个或多个(’*’)任意字符(’.’)

思路- -动态规划- - 自顶向下:
一、首先考虑自顶向下的算法,因为自顶向下算法需要完成一个来回,从前向后进行推导,故当自顶向下算法理解后就很容易理解自底向上算法。
二、在自顶向下算法中,假定使用符号s[i:]表示字符串s中从第i个字符到最后一个字符组成的子串,p[j:]则表示模式串p中,从第j个字符到最后一个字符组成的子串,使用match(i,j)表示s[i:]与p[j:]的匹配情况,如果能匹配,则置为true,否则置为false,此为各个子问题以及子问题的状态。
三、在本问题中,match(i,j)能否匹配,完全取决于p[j+1]是否为“* ”,故由此可得到此次动态规划的状态转移方程
curMatch = i < s.length() && s[i] == p[j] || p[j] =="."

  1. p[j+1] != "* ", match(i,j) = curMatch && match(i+1, j+1)
  2. p[j+1] == "* " , match(i,j) = match(i, j+2) || curMatch && match(i+1, j)

Code- - 自顶向下的动态规划

enum Result {
	TRUE, FALSE;  //枚举结果
}
class Solution {
	Result[][] memo;
	public boolean isMatch(String s, String p) {
		memo = new Result[s.length()+1][p.length()+1];
		return match(0, 0, s, p};
	}
	public boolean match(int i, int j, String s, String p) {
		if (memo[i][j] != null) {
			return memo[i][j] == Result.TRUE;
		}
		boolean ans;
		if (j == p.length()) {
		//如果pattern已经遍历结束
			ans = i == s.length();
		} else {
		//第一位的判断和原来类似
			boolean curMatch = (i < s.length() && (p.charAt(j) == s.charAt(j) || p.charAt(j) == "."));
			if (j + 1 < p.length() && p.charAt(j + 1) == "* ") {
				ans = match(i, j + 2, s, p) || curMatch && match(i+1, j, s, p); 
			} else {
				ans = curMatch && match(i+1, j+i, s, p);
			}
		}
		//保存临时结果
		memo[i][j] = ans ? Result.TRUE : Result.FALSE; //此句仅是对上文代码中的判空结果做一个双重肯定
		return ans;
	}
}

思路分析- -动态规划自底向上:

  1. 其实代码的核心还是位于判断j+1处是否为"* " 这个符号,故此处同自顶向下相同。
  2. 自底向上采取从后往前处理,即在二维数表中是向左向上前进,这样一来,就避免掉了默认值的问题,同时也不需要像上面一样引入一个看起来很奇怪的枚举值。
  3. 数组边缘值也很容易进行判断

Code- - 动态规划自底向上:

class Solution {
	boolean[][] dp = new boolean[s.length()+1][p.length()+1];
	dp[s.length()][p.length()] = true;
 	
 	for(int i = s.length(); i >= 0; i--) { //i无法从s-1开始
 		for(int j = p.length()-1; j >= 0; j--) { //如果j从p.length()开始的话会产生越界错误
			//核心代码保持不变
			//此处不用判断是否为空的问题
			boolean curMatch = i < s.length() && (s.charAt(i) == p.charAt(j) || p.charAt(j) == "."); //在判断为false后就不会执行后边的操作,所以无须担心i+1会越界
			//判断* 号
			if (j+1 < p.length() && p.charAt(j+1) == "* ") {
			//出现0次
			//出现1次或多次
				dp[i][j] = dp[i][j+2] || curMatch && dp[i+1][j];
			} else {
				dp[i][j] = curMatch && dp[i+1][j+1];
			}
 		}
 	}
 	//直接返回最终结果即可
 	return dp[0][0];
}

ps1问题:code2中i无法从s-1开始,因为由一个测试用例无法通过 s= “aa”, p=“a*”
PS2:之后有时间会对动态规划类题算法题作出自己的总结和见解。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值