带有通配符的字符串匹配
一、Leetcode | 44 Wildcard Matching(只有一个字符串包含通配符)
题目很简单,就是说两个字符串,一个含有通配符,去匹配另一个字符串;输出两个字符串是否一致。
注意:’?’表示匹配任意一个字符,’*’表示匹配任意字符0或者多次
首先,我们想到暴力破解。如果从头到尾的破解,到第二个字符时,是否匹配成功取决于第一个字符是否匹配成功! 所以我们想到应该要用到动态规划;
于是,我们开始分析初值怎么设;其实很简单,把这个匹配问题可以想象成一个矩阵dp,纵轴代表含有通配符的匹配字符串s2, 横轴代表要匹配的字符串s1。假设现在s2=”a*b”, s1=”abc” 如图:
对应空位就是截止到当前的 (i,j) 位置,两字符串是否匹配。匹配为 T(true),不匹配为 F(false),最后返回最右下角的值,就是当前两个字符串是否匹配的最终值;
此时初值已经设置完毕,我们要找到递推式;经局部推算,我们发现递推式应该有两种,一种是当s2的字符是星号,另一种是s2的字符是非星号。
//isMatch: s1无通配符,s2有通配符, '?'表示匹配任意一个字符,'*'表示匹配任意字符0或者多次
public static boolean isMatch(String s1, String s2) {
int countXing = 0;
for(char c : s2.toCharArray())
countXing++;
if(s2.length() - countXing > s1.length() ) //说明s2去掉通配符,长度也长于s1
return false;
//动态规划设置初值
boolean[][] dp = new boolean[s2.length()+1][s1.length()+1];
dp[0][0] = true;
for(int i=1; i<=s2.length(); i++) {
char s2_char = s2.charAt(i-1);
dp[i][0] = dp[i-1][0] && s2_char=='*'; //设置每次循环的初值,即当星号不出现在首位时,匹配字符串的初值都为false
for(int j=1; j<=s1.length(); j++) {
char s1_char = s1.charAt(j-1);
if(s2_char == '*')
dp[i][j] = dp[i-1][j] || dp[i][j-1]; //动态规划递推式(星号) 表示星号可以匹配0个(决定于上次外循环的结果)或者多个(决定于刚才内循环的结果)
else
dp[i][j] = dp[i-1][j-1] && (s2_char=='?' || s1_char == s2_char); //动态规划递推式(非星号) 表示dp值取决于上次的状态和当前状态
}
}
return dp[s2.length()][s1.length()];
}
//方法二:字符串通配符(牛客超时,内有解决方法)
//方法二:字符串通配符
public static boolean getOc(String in,String temp){
in = in.toUpperCase();
temp = temp.toUpperCase();
in = in.replaceAll("(\\*)\\1{1,}","*");//将连续的“*”,替换成一个“*”,牛客超时
//字符串通配符
in = in.replaceAll("\\?", "[0-9A-Za-z]{1}");
in = in.replaceAll("\\*", "[0-9A-Za-z]{0,}");
//in = in.replaceAll("\\.", "\\\\.");
return temp.matches(in);
}
//方法一:递归(牛客超时).s1匹配,p1为s1索引,s2为目标串,p2为s2索引
//方法一:递归.s1匹配,p1为s1索引,s2为目标串,p2为s2索引
public static boolean judge(String s1, String s2, int p1, int p2) {
//把s1的连续多个“*”变为1一个‘*’,
s1 = s1.replaceAll("(\\*)\\1{1,}","*");//replace替换char和string。replaceAll将正则表达式替换成String
s1 = s1.toUpperCase();
s2 = s2.toUpperCase();
if(p1 == s1.length() && p2 == s2.length()) {
return true;
}
if(p1 == s1.length() || p2 == s2.length()) {
return false;
}
if(s1.charAt(p1) == '*') {
//匹配多个judge(s1,s2,p1,p2+1),匹配0个judge(s1,s2,p1+1,p2);匹配1个judge(s1,s2,p1+1,p2+1);
return judge(s1,s2,p1,p2+1) || judge(s1,s2,p1+1,p2) || judge(s1,s2,p1+1,p2+1);
}else if(s1.charAt(p1) == '?' || s1.charAt(p1) == s2.charAt(p2)) {
return judge(s1,s2,p1+1,p2+1);
}else {
return false;
}
}