【每日一题】day18_01 字符串通配符

学习目标:

目标:熟练运用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],这两个位置有一个是 truedp[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)=='*';
           }

图解:
在这里插入图片描述

  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;
        }
    }
}
  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值