给定一个字符串 (s) 和一个字符模式 (p) ,实现一个支持 '?' 和 '*' 的通配符匹配。
'?' 可以匹配任何单个字符。
'*' 可以匹配任意字符串(包括空字符串)。
两个字符串完全匹配才算匹配成功。
说明:
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母,以及字符 ? 和 *。
示例 1:
输入:
s = "aa"
p = "a"
输出: false
解释: "a" 无法匹配 "aa" 整个字符串。
示例 2:
输入:
s = "aa"
p = "*"
输出: true
解释: '*' 可以匹配任意字符串。
示例 3:
输入:
s = "cb"
p = "?a"
输出: false
解释: '?' 可以匹配 'c', 但第二个 'a' 无法匹配 'b'。
示例 4:
输入:
s = "adceb"
p = "*a*b"
输出: true
解释: 第一个 '*' 可以匹配空字符串, 第二个 '*' 可以匹配字符串 "dce".
示例 5:
输入:
s = "acdcb"
p = "a*c?b"
输出: false
大神果然很多,各种题目都能玩出花样。 膜拜。。。。。
package com.atchina;
public class WildCardMatching {
public static void main(String[] args) {
String s = "acdcb";
String p = "a*b";
System.out.printf("isMatch1: %s is match %s: %b\n", s, p, isMatch1(s, p));
System.out.printf("isMatch2: %s is match %s: %b\n", s, p, isMatch2(s, p));
// System.out.println(ss.charAt(0) == '1');
// System.out.println(ss.length());
}
// 最简单的版本
public static boolean isMatch1(String s, String p){
int m = s.length();
int n = p.length();
s = "a"+s; // 在字符串前面加一个随意的字符,方便从下标1开始遍历
p = "a"+p;
// dp[i][j]表示s的前i个字符是否可以和p的前j个字符匹配
int[][] dp = new int[m+1][n+1];
dp[0][0] = 1;
//当s为空的时候,给[0][i]赋初值
for(int x=1; x<=n;x++){
if(p.charAt(x) != '*'){
break;
}
dp[0][x] = 1;
}
//遍历两个字符串,为dp[i][j]依次赋值
//dp[i][j]=true有三种可能
//(1)dp[i-1][j-1]=true并且s.charAt(i-1)=p.charAt(j-1) 或者p.charAt(j-1) = ‘?’
//(2)dp[i][j-1]=true并且p.charAt(j-1)="*"
//(3)dp[i-1][j]=true并且p.charAt(j-1)="*"
// s = "acdcb";
// p = "a*b"
for (int i=1; i<=m; i++){
for(int j=1; j<=n;j++){
if(p.charAt(j) == '?'){
dp[i][j] = dp[i-1][j-1];
}else if(p.charAt(j)== '*'){
for(int k=0; k<=i; k++){
if(dp[k][j-1] == 1){
dp[i][j] = 1;
}
}
}else if(s.charAt(i) == p.charAt(j)){
dp[i][j] = dp[i-1][j-1];
}
}
}
return dp[m][n] == 1 ? true : false;
}
// 优化版1
public static boolean isMatch2(String s, String p){
int m = s.length();
int n = p.length();
s = "a"+s;
p = "a"+p;
int[][] dp = new int[m+1][n+1];
dp[0][0] = 1;
for(int x=1; x<=n;x++){
if(p.charAt(x) != '*'){
break;
}
dp[0][x] = 1;
}
// s = "acdcb";
// p = "a*b"
for (int i=1; i<=m; i++){
for(int j=1; j<=n;j++){
if(p.charAt(j) == '?'){
dp[i][j] = dp[i-1][j-1];
}else if(p.charAt(j)== '*'){
// for(int k=0; k<=i; k++){
// if(dp[k][j-1] == 1){
// dp[i][j] = 1;
// }
// }
//dp[i][j-1] 即当前'*'匹配一个空字符
//dp[i-1][j] 即当前'*'匹配一个字符s.charAt(i-1)
//这里之所以不是dp[i-1][j-1]是因为当前'*'可能在前面已匹配了若干个字符
// 这里进行优化,不使用循环
if(dp[i][j-1]== 1 || dp[i-1][j]== 1){
dp[i][j] = 1;
}else{
dp[i][j] = 0;
}
}else if(s.charAt(i) == p.charAt(j)){
dp[i][j] = dp[i-1][j-1];
}
}
}
return dp[m][n] == 1 ? true : false;
}
// 优化版2 时间复杂度 O(n)
public static boolean isMatch(String s, String p){
int sp = 0;
int pp = 0;
int match = 0;
int start = -1;
while(sp<s.length()){
if(pp<p.length() && (s.charAt(sp) == p.charAt(pp) || p.charAt(pp) == '?')){
sp++;
pp++;
}else if(pp<p.length() && p.charAt(pp) == '*'){
start = pp;
match = sp;
pp++;
}else if(start != -1){
pp = start + 1;
match++; // 这就表示*可以匹配任意长的字符串
sp = match;
}else{
return false;
}
}
// 处理最后字符是*的问题 比如 s = "abcefcb"; p="a*cb*",或者p="a*cb*****"等等
while(pp < p.length() && p.charAt(pp) == '*'){
pp++;
}
//System.out.println(match);
return pp == p.length();
}
}