题解 | #正则表达式匹配#
正则表达式匹配
http://www.nowcoder.com/practice/28970c15befb4ff3a264189087b99ad4
题目
描述
- 请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但是与"aa.a"和"ab*a"均不匹配
方法一
思路
- pattern中总共分为三种字符,普通字符,'.','*',其中普通字符与'.'很好处理,只要与str中相应位置的字符比较即可,对于普通字符只要判断是否相同,而字符'.'则只要str对应位置不为空即可;
- 对于字符'*',需要考虑忽略前面一个字符或者是拓展前面一个字符,便存在如下递推公式:
前提是前面的字符串已经匹配成功, ,分别表示'*'匹配多个字符以及不匹配字符。
具体步骤
- 代码如下:
import java.util.*; public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param str string字符串 * @param pattern string字符串 * @return bool布尔型 */ public boolean match (String str, String pattern) { if (pattern.length() == 0) { return str.length() == 0; } // 第一个字符必然不会是'*',所以可以直接比较 boolean match = (str.length() > 0 && (str.charAt(0) == pattern.charAt(0) || pattern.charAt(0) == '.')); // 有* if (pattern.length() > 1 && pattern.charAt(1) == '*') { // 0个 || 多个 return match(str, pattern.substring(2)) || (match && match(str.substring(1), pattern)); } // 无* else { return match && match(str.substring(1), pattern.substring(1)); } } }
- 时间复杂度:,JDK的substring的时间复杂度为,而匹配需要;
- 空间复杂度:,遍历str以及pattern。
方法二
思路
- 采用动态规划的方法解题,创建二维数组dp,dp[i][j]表示从0~i-1的str与从0~j-1的pattern是否匹配,匹配为true,反之则为false;
- pattern中总共分为三种字符,普通字符,'.','*',其中普通字符与'.'很好处理,只要与str中相应位置的字符比较即可,对于普通字符只要判断是否相同,而字符'.'则只要str对应位置不为空即可;
- 最为复杂的就是字符'*',该字符可以匹配0或多个前面的字符,所以需要考虑以下两种情况:
- a.当前位pattern[j-1] == '*',那么需要判断以下三种情况:
- dp[i][j - 2],即 j-2 位 的pattern能满足,则 i-1 位是 '*' 作为任意数量的值必定能满足匹配
- dp[i - 1][j] && str[i - 1] == pattern[j - 2];即让字符 pattern[j-2]多出现几次,看能否匹配
- dp[i - 1][j] && pattern[j - 2] == '.', 即让字符 '.' 多出现 1 次时,能否匹配;
- b.当前位pattern[j-1] != '*',那么只需要判断当前位是否满足条件即能否匹配到str对应位i,可以dp[i+1][j+1] = true。
- 初始化,考虑字符串为空,但是pattern不为空的情况:dp[0][j] = dp[0][j - 2] 且 p[j - 1] = '*', 即当前pattern的0到j位是true还是false,取决于dp[0][j-2]是否匹配,以及 pattern的当前位的上一位是否为'*'。
- Tip:这里有个有点绕的下标表示,对于dp来说下标0表示空串,而对于str以及pattern来说,下标0表示第一个字符。
具体步骤
- 参考下图示例
- 代码如下
import java.util.*; public class Solution { /** * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 * * * @param str string字符串 * @param pattern string字符串 * @return bool布尔型 */ public boolean match (String str, String pattern) { // 加上空串,0~n boolean[][] dp = new boolean[str.length()+1][pattern.length()+1]; // 两个都是空串 dp[0][0] = true; // 字符串为空,正则表达式不为空 for (int i = 2; i < dp[0].length; ++i){ // 正则表达式从下标0开始 if (pattern.charAt(i-1) == '*'){ // 从下标1开始 dp[0][i] = dp[0][i-2]; } } // 状态转移 for (int i = 1;i < dp.length;++i){ for (int j = 1;j < dp[0].length;++j){ if (pattern.charAt(j-1) != '*'){ if (pattern.charAt(j-1) == '.' || pattern.charAt(j-1) == str.charAt(i-1)){ dp[i][j] = dp[i-1][j-1]; } }else if (j >= 2 && pattern.charAt(j - 1) == '*'){ // 对于包含 * 的匹配 // 当前一位为 '.', 或者字符相等,则匹配 if (pattern.charAt(j - 2) == '.' || pattern.charAt(j - 2) == str.charAt(i - 1)) { dp[i][j] = dp[i][j - 2] || dp[i - 1][j - 2] || dp[i - 1][j]; } else { // 否则只能不匹配 dp[i][j] = dp[i][j - 2]; } } } } return dp[str.length()][pattern.length()]; } }
- 时间复杂度:,m = str.length(),n = pattern.length(),遍历整个dp数组;
- 空间复杂度:,二维数组dp。