LeetCode-Regular Expression Matching

算法分析与设计,第三周博客。

Regular Expression Matching

Implement regular expression matching with support for '.' and '*'.

'.' Matches any single character.
'*' Matches zero or more of the preceding element.

The matching should cover the entire input string (not partial).

The function prototype should be:
bool isMatch(const char *s, const char *p)

Some examples:
isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "a*") → true
isMatch("aa", ".*") → true
isMatch("ab", ".*") → true
isMatch("aab", "c*a*b") → true

本题的意思是,给出一个字符串s和另一个字符串p,比较s和p是否匹配。其中p中可能含有通配符'.',点号可以代表任意一个字符,另一个特殊符号是'*',星号代表在此之前出现的符号出现零次或多次。

如果p中不包含点号或者星号,那么很简单,直接比较两个字符串是否一样就好了。然后是如果p中不包含星号,那么这种情况下也很简单,比较这两个字符串的每个字符是否相等,其中 点号可以代表任意字符。最后的情况就是p中含有星号了,重点就是,在这种情况下,又该如何处理呢。

设dp[i][j] = true 如果字符串s从下标i开始的子串与字符串p从下标j开始的子串匹配。那么最后只需要返回dp[0][0],就能代表字符串s和字符串p的匹配结果。

我们一个字符一个字符的来比较:

  1. if (p[j+1] != '*')  dp[i][j] = (p[j] == '.' || p[j] == s[i]) && dp[i+1][j+1]; 这个情况还是挺直观的,当p的第j个字符的下一个字符不是星号的时候,此时两个字符的匹配只与当前两个字符串的对应字符有关,只需要比较这两个字符串能否匹配就好了。然后进一步看比较剩下的部分是否匹配,即dp[i+1][j+1]是否为真。
  2. if (p[j+1] == '*') dp[i][j] = dp[i][j+2] || ((p[j] == '.' || p[j] == s[i]) && dp[i+1][j]);这种情况下稍微比上一种情况复杂,此时的结果由两部分组成, dp[i][j+2] 和(p[j] == '.' || p[j] == s[i]) && dp[i+1][j]。先来看第二部分,这一个部分和上一种情况还是挺相似的,比较当前两个字符是否匹配,并进一步比较剩下的字符串。这里和情况1的不同点在于,一个字符后面含有星号,就意味着这个字符可能出现多次,现在先假设这个字符已经出现了一个并成功匹配了,因为如果不满足这个假设,那么后面那部分的结果就必然会在p[j] == '.' || p[j] == s[i]阶段就返回false,从而不需要进行进一步的判断了。所以我们这个假设是有意义和道理的,那么现在当前字符已经出现一次了,我们有理由相信它有可能会再次出现,所以进一步的判断是看dp[i+1][j]的结果。讨论完第二部分,再返回讨论第一部分的。其实结果已经很显然了,在第二部分中,星号的存在使得当前字符至少出现了一次。而星号的存在是让前一个字符出现零次或者多次。多次的结果已经在第二部分讨论过了,那么第一部分就是星号之前的字符并没有出现的情况,也就是,当前字符与它的下一个字符,星号,并没有出现在匹配过程中,也就是字符串p跳过了这两个字符,直接进行下一步的匹配,所以结果就是dp[i][j+2]。有了这两个部分,那么带有星号的情况也被解决了。
所实现的代码如下所示:
boolean match(String s, int i, String p, int j, int[][] dp) {
		if (j >= p.length())
			return i >= s.length();
		if (i >= s.length())
		{
			while (j+1 < p.length()) {
				int k = j;
				if (p.charAt(j+1) == '*') {
					j = j+2;
				}
				if (k == j)
					break;
			}
			return j >= p.length();
		}
		
		
		if (j+1 < p.length()) {
			if (p.charAt(j+1) == '*') {
				if (j+2 < p.length())
				{
					if (dp[i][j+2] == 0) {
						dp[i][j+2] = match(s, i, p, j+2, dp) ? 1 : -1;
					}
					boolean unused = dp[i][j+2] == 1;
					if (unused)
						return true;
				}
				if (p.charAt(j) == '.' || s.charAt(i) == p.charAt(j))
				{
					dp[i][j] = match(s, i+1, p, j, dp) ? 1 : -1;
					return dp[i][j] == 1;
				}
			}
		}
		if (p.charAt(j) == '.' || s.charAt(i) == p.charAt(j))
		{
			dp[i][j] = match(s, i+1, p, j+1, dp) ? 1 : -1;
			return dp[i][j] == 1;
		}
		dp[i][j] = -1;
		return false;
	}
	
	
	public boolean isMatch(String s, String p) {
		int[][] dp = new int[s.length()][p.length()];
		return match(s, 0, p, 0, dp);
    }

因为一开始实现的时候并没有用数组保存状态,而是使用递归调用的方法,所以这个版本写出来是在递归的版本上进行修改得到的,虽然和传统的动态规划的形式不一样,但实际上是一致的。最后来看下这个算法的时间复杂度,申明了一个数组dp,大小为|s|*|p|,当为这个数组的每个位置都赋值时,结果就出来了,而为每一个位置赋值的时间复杂度是O(1),进行了若干次的比较,所以整个算法的时间复杂度和空间复杂度都是O(|s|*|p|)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LeetCode-Editor是一种在线编码工具,它提供了一个用户友好的界面编写和运行代码。在使用LeetCode-Editor时,有时候会出现乱码的问题。 乱码的原因可能是由于编码格式不兼容或者编码错误导致的。在这种情况下,我们可以尝试以下几种解决方法: 1. 检查文件编码格式:首先,我们可以检查所编辑的文件的编码格式。通常来说,常用的编码格式有UTF-8和ASCII等。我们可以将编码格式更改为正确的格式。在LeetCode-Editor中,可以通过界面设置或编辑器设置来更改编码格式。 2. 使用正确的字符集:如果乱码是由于使用了不同的字符集导致的,我们可以尝试更改使用正确的字符集。常见的字符集如Unicode或者UTF-8等。在LeetCode-Editor中,可以在编辑器中选择正确的字符集。 3. 使用合适的编辑器:有时候,乱码问题可能与LeetCode-Editor自身相关。我们可以尝试使用其他编码工具,如Text Editor、Sublime Text或者IDE,看是否能够解决乱码问题。 4. 查找特殊字符:如果乱码问题只出现在某些特殊字符上,我们可以尝试找到并替换这些字符。通过仔细检查代码,我们可以找到导致乱码的特定字符,并进行修正或替换。 总之,解决LeetCode-Editor乱码问题的方法有很多。根据具体情况,我们可以尝试更改文件编码格式、使用正确的字符集、更换编辑器或者查找并替换特殊字符等方法来解决这个问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值