一、题目
给你一个字符串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
解释:.*
表示可匹配零个或多个(*
)任意字符(.
)。
提示:
- 1 <= s.length <= 20
- 1 <= p.length <= 20
- s只包含从a-z的小写字母。
- p只包含从a-z的小写字母,以及字符.和*。
- 保证每次出现字符*时,前面都匹配到有效的字符
二、题解
- 创建对应的二维数组,存放相应的动态规划结果,该数组从最小开始,即两个字符串都是空开始
- 使得初始状态为真
双层for循环,遍历字符串,逐步拓展- 当前字符前前面为*时,
abbbc
和ab*c
- b 3 b_3 b3和d位置,应当是*复制b,因此,需要tf[i][j]=tf[i][j-2]
- 当前字符前前面为*时,
aadc
和a*adc
- 应当是跳过*,因此需要tf[i][j]=tf[i-1][j]
- 当前字符前前面为*时,
aaadc
和a*adc
- a 3 a_3 a3和 a 3 a_3 a3位置,应当是*复制一个a,因此,需要tf[i][j]=tf[i][j]
- 若前面不是*,比较当前位置,拓展即可
- 当前字符前前面为*时,
在此过程中,多次使用到对比函数,因此将其取出,单独描述
- 当s字符串为空时直接为false
- 当
p.charAt(j - 1)
是'.'
,可以匹配任意单个字符,因此肯定为true - 无特殊情况是,对比字符串转字符数组当前值,返回比较结果
注意,由于对应的动态规划数组从两者为空开始记录,所以i、j 比相应的数组角标大1,所以转为角标时应当减去1
三、代码
import java.util.Scanner;
public class IsMatch_10_Self {
// 动态规划
// a b b b b c
// a b * d * c
public static boolean isMatch(String s, String p){
int m = s.length(), n = p.length();
boolean[][] tf = new boolean[m + 1][n + 1];
// i -> s , j-> p
tf[0][0] = true; // 指向字符串前
for(int i = 0; i <= m; i++){
for(int j = 1; j <= n; j++){
if(p.charAt(j -1) == '*'){
tf[i][j] = tf[i][j - 2];
if (match(s, p, i, j - 1)) {
tf[i][j] = tf[i][j] || tf[i - 1][j]; //addc a*d*c 需要跳过第一个* ,tf[i][j] = tf[i-1][j]
}
}else{
if (match(s, p, i, j)) {
tf[i][j] = tf[i - 1][j - 1];
}
}
}
}
return tf[m][n];
}
// 对比函数
public static boolean match(String s, String p, int i, int j){
if(i == 0){
return false;
}
if(p.charAt(j - 1) == '.'){ // '.'匹配任意字符
return true;
}
return s.charAt(i - 1) == p.charAt(j - 1);
}
public static void main(String[] args){
Scanner scs = new Scanner(System.in);
String s = scs.nextLine();
Scanner scp = new Scanner(System.in);
String p = scp.nextLine();
System.out.println(isMatch(s,p));
}
}
四、结果
五、说明
本文章仅用于记录个人做题记录
由于本人是个小菜鸡(实锤),题目解法并非最优,且解题过程中参考(抄袭)各大佬解题方法,望见谅。