10,正则表达式匹配
给你一个字符串 s
和一个字符规律 p
,请你来实现一个支持 '.'
和 '*'
的正则表达式匹配。
-
'.'
匹配任意单个字符 -
'*'
匹配零个或多个前面的那一个元素 -
'*'
匹配零个或多个前面的那一个元素
所谓匹配,是要涵盖 整个 字符串 s
的,而不是部分字符串。
示例 1:
输入:s = "aa", p = "a"
输出:false
解释:"a" 无法匹配 "aa" 整个字符串。
示例 2:
输入:s = "aa", p = "a*"
输出:true
解释:因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。
示例 3:
输入:s = "ab", p = ".*"
输出:true
解释:".*" 表示可匹配零个或多个('*')任意字符('.')。
思路分析
该题是用动态规划的思路去完成的。之后会出一篇专门讲解动态规划的文章。
代码实现(建议复制后去idea中观看)
/**
* @version v1.0
* @ProjectName: 数据结构
* @ClassName: Solution10
* @Description: 请描述该类的功能
* @Author: 赵先生
* @Date: 2022/3/4 10:12
*/
public class Solution10 {
public boolean isMatch(String s, String p) {
//获取字符串和匹配规则的长度
int sLen = s.length(), pLen = p.length();
//创建一个二维数组,填写可能出现的结果
boolean[][] memory = new boolean[sLen+1][pLen+1];
//因为如果s和p都为空的,那么他们是匹配的
memory[0][0] = true;
for(int i = 0; i <= sLen; i++) {
//j从1开始是因为在[0][0]处我们已经初始化过了,而当i不为0的时候,j如果为0肯定不匹配,没有讨论的意义。
for(int j = 1; j <= pLen; j++) {
//如果p的最后一个字符为*,则需要进行讨论。因为*可以代表一个前字符的任意数
if(p.charAt(j-1) == '*') {
/**
* 如果*表示0个数,就说明s的最后一个字符必须要和p倒数第2个字符前要相等 memory[i][j-2]
* 如果*表示1个数,就说明除了最后一个字符以外要和p的倒数第2个字符前要相等,且s的最后一个字符和p的倒数第2的
* 数相等 memory[i-1][j-2] && s.charAt(i-1) == p.charAt(j - 2)
* 如果*表示2个数,就说明除了最后两个个字符以外要和p的倒数第2个字符前要相等,且s的最后一,二个字符和p的倒数第2的数相等
* memory[i-2][j-2] && s.charAt(i-1) == p.charAt(j - 2) && s.charAt(i-2) == p.charAt(j - 2)
* ...
* 换作表达式为 memory[i][j] = memory[i][j-2] || (memory[i-1][j-2] && s.charAt(i-1) == p.charAt(j - 2)) || (memory[i-2][j-2] && s.charAt(i-1) == p.charAt(j - 2) && s.charAt(i-2) == p.charAt(j - 2)) || ...
* 但是为了简化步骤,所以将后两个步骤整合
* memory[i-1][j] = memory[i-1][j-2] || (memory[i-2][j-2] && s.charAt(i-2) == p.charAt(j - 2)) || (memory[i-3][j-2] && s.charAt(i-2) == p.charAt(j - 2) && s.charAt(i-3) == p.charAt(j - 2)) || ...
* 这个时候发现memory[i-1][j] 是可以替换掉 (memory[i-1][j-2] && s.charAt(i-1) == p.charAt(j - 2)) || (memory[i-2][j-2] && s.charAt(i-1) == p.charAt(j - 2) && s.charAt(i-2) == p.charAt(j - 2)) || ...
* 变为memory[i][j] = memory[i][j-2] || (i > 0 && (s.charAt(i-1) == p.charAt(j-2) || p.charAt(j-2) == '.') && memory[i-1][j])
*/
memory[i][j] = memory[i][j-2] || (i > 0 && (s.charAt(i-1) == p.charAt(j-2) ||
p.charAt(j-2) == '.') && memory[i-1][j]);
}else {
//如果p[j]中没有*号,那么必须满足i是大于0的,且这s[i-1]和p[j-1]是相等的或者有何p的最后一个字符为. 前面条件成立
//的前提是他们他们memory[i-1][j-1]是成立的。
memory[i][j] = i > 0 && (s.charAt(i-1) == p.charAt(j-1) || p.charAt(j-1) == '.')
&& memory[i-1][j-1];
}
}
}
return memory[sLen][pLen];
}
}