学习目标:
目标:熟练运用Java所学知识
学习内容:
本文内容:使用java解决 字符串通配符
题目描述
链接:https://www.nowcoder.com/questionTerminal/43072d50a6eb44d2a6c816a283b02036
来源:牛客网
问题描述:
在计算机中,通配符一种特殊语法,广泛应用于文件搜索、数据库、正则表达式等领域。现要求各位实现字符串通配符的算法。 要求:
实现如下2个通配符:
*:匹配0个或以上的字符(字符由英文字母和数字0-9组成,不区分大小写。下同) ?:匹配1个字符
输入:
通配符表达式;
一组字符串。
输出:
返回匹配的结果,正确输出true,错误输出false
本题含有多组样例输入!
输入描述:
先输入一个带有通配符的字符串,再输入一个需要匹配的字符串
输出描述:
返回匹配的结果,正确输出true,错误输出false
示例1
输入
te?t*.*
txt12.xls
输出
false
解题思路
这个题目有两种解法一种是动态规划,一种是深度优先算法
1.动态规划
定义c1是带有通配符的字符串对应的字符数组,c2是待匹配的字符串对应字符数组
状态:dp[i][j] 表示以c1的第 i-1 个字符结尾的字符串和以 c2 的第 j-1 个字符结尾的字符串的匹配情况,true表示匹配,false表示不匹配
-
当前状态分为三种情况:
①该位置在带有通配符的字符串对应的字符是* (c1[i-1]=’*’)
②该位置在带有通配符的字符串对应的字符是? (c1[i-1]=’?’)
③该位置在带有通配符的字符串对应的字符是正常字母 (c1[i-1]是字母) -
当 c1[i-1] 是 * 时,该位置的状态 dp[i][j] 取决于 dp[i][j-1] 或 dp[i-1][j],这两个位置有一个是 true 时 dp[i][j] 就是true,因为*可以匹配0个、一个或多个。当 dp[i][j] 的 true 取决于 dp[i-1][j] 时,表示匹配0个;取决于 dp[i][j-1] 表示匹配一个或多个
-
当 c1[i-1] 是 ?时,该位置的状态 dp[i][j] 取决于dp[i-1][j-1],表示当两个字符串的前一个位置匹配时,当前位置就匹配
-
当 c1[i-1] 是字母时,该位置的状态 dp[i][j] 取决于 dp[i-1][j-1] 与c1[i]==c2[j],只有前一个位置匹配且当前位置的字母相等,dp[i][j] 才是 true
递推关系:
初始化:
- 将dp[0][0]初始化为true,因为对应的字符都是空
- 将第0行其他的都初始化为false
- 第0列的初始化取决于上一行的第0列和当前行的带有通配符的字符串是不是*
- 只有当上一行第0列是true且当前位置的带有通配符的字符串对应的字符是*,才是true
代码表示:
dp[0][0]=true;
for(int i=1;i<matrix.length;i++){
dp[i][0]=dp[i-1][0]&&str1.charAt(i-1)=='*';
}
图解:
- 深度优先搜索:
深度优先递归时的退出条件是①当两个字符串递归的位置都等于字符串长度返回true②只有其中一个字符串递归的位置等于长度,返回false
递归时分为四种情况
1 带通配符字符串递归的位置是*
2 .带通配符字符串递归的位置是?
3.两个字符串递归的位置字符相等
4.两个字符串递归的位置字符不相等
实现代码
- 动态规划:
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
while(sc.hasNext()){
String str1=sc.next();
String str2=sc.next();
//存放每一个位置状态的数组
boolean[][] dp =new boolean[str1.length()+1][str2.length()+1];
dp[0][0]=true;//初始化
//初始化
for(int i=1;i<dp.length;i++){
dp[i][0]=dp[i-1][0]&&str1.charAt(i-1)=='*';
}
for(int i=1;i<dp.length;i++){
for(int j=1;j<dp[0].length;j++){
if(str1.charAt(i-1)=='*'){
//当前位置带有通配符的字符串对应的字符是*
dp[i][j]=dp[i-1][j]||dp[i][j-1];
}else if(str1.charAt(i-1)=='?'){
//当前位置带有通配符的字符串对应的字符是?
dp[i][j]=dp[i-1][j-1];
}else{
//当前位置带有通配符的字符串对应的字符是字母
dp[i][j]=dp[i-1][j-1]&&str1.charAt(i-1)==str2.charAt(j-1);
}
}
}
System.out.println(dp[str1.length()][str2.length()]);
}
}
}
- 深度优先算法
import java.util.Scanner;
public class Wildcard2 {
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
while(sc.hasNext()){
String str1=sc.next();
String str2=sc.next();
System.out.println(match(str1,str2,0,0));
}
}
public static boolean match(String str1, String str2, int a, int b){
if(a==str1.length()&&b==str2.length()){
//退出条件1
return true;
}
if(a==str1.length()||b==str2.length()){
//退出条件2
return false;
}
if(str1.charAt(a)=='*'){
//带通配符字符串递归的位置是*
return match(str1,str2,a+1,b)|| match(str1,str2,a+1,b+1)|| match(str1,str2,a,b+1);
}else if(str1.charAt(a)=='?'){
//带通配符字符串递归的位置是?
return match(str1,str2,a+1,b+1);
}else if(str1.charAt(a)==str2.charAt(b)){
//两个字符串递归的位置字符相等
return match(str1,str2,a+1,b+1);
}else{
//两个字符串递归的位置字符不相等
return false;
}
}
}