Leetcode 10. 正则表达式匹配
问题描述;
给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配。
'.' 匹配任意单个字符
'*' 匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。说明:
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 . 和 *。
示例 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来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/regular-expression-matching
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
动态规划
dp[i][j]表示到下标为i的s串的子串和到标号为j的p串的子串能否匹配。
分三种情况讨论
1, If p.charAt(j) == s.charAt(i) : dp[i][j] = dp[i-1][j-1];
2, If p.charAt(j) == '.' : dp[i][j] = dp[i-1][j-1];
3, If p.charAt(j) == '*':
两种子情况:
1 if p.charAt(j-1) != s.charAt(i) : dp[i][j] = dp[i][j-2] //*前的字母和s的最后一个字母不匹配,*的含义即为0个字符
2 if p.charAt(i-1) == s.charAt(i) or p.charAt(i-1) == '.': //如果*代表一个或者多个,那*前的字母必须和s最后一个匹配
dp[i][j] = dp[i-1][j] // a* 被认为是多个 a
or dp[i][j] = dp[i][j-1] //a* 被认为是1个 a
or dp[i][j] = dp[i][j-2] //a* 被认为是0个 a
/** * * @param s=待匹配字符串 * @param p=正则表达式 * @return true or false * 所有i,j表示从1开始的下标,表示实际下标要减一 */ public static boolean isMatch(String s, String p) { int lenS=s.length(); int lenP=p.length(); boolean dp[][]=new boolean[lenS+1][lenP+1]; dp[0][0]=true; //初始化dp[0][j],在每个*都代表0的时候和""匹配 for (int j = 2; j <= lenP; j++) { if(p.charAt(j-1)=='*'){ if(dp[0][j-2]){ dp[0][j]=true; } } } for (int i = 1; i <= lenS; i++) { for (int j = 1; j <= lenP; j++) { if(s.charAt(i-1)==p.charAt(j-1)){ dp[i][j]=dp[i-1][j-1]; } else if(p.charAt(j-1)=='.'){ dp[i][j]=dp[i-1][j-1]; } else if(p.charAt(j-1)=='*'){ dp[i][j]=(s.charAt(i-1)==p.charAt(j-2)||p.charAt(j-2)=='.')&& (dp[i-1][j]||dp[i][j-1])||(dp[i][j-2]); } } } return dp[lenS][lenP]; }