题解 | #字符串通配符#
字符串通配符
https://www.nowcoder.com/practice/43072d50a6eb44d2a6c816a283b02036
HJ71 字符串通配符--dp求解
解题步骤:
- 先将目标串s中的大写字母转化为小写字母
- 定义动态规划方程意义,dp[i][j]表示表示p(包含*?的模式串)的前i个字符是否能与s的前j个字符匹配
- 定义动态规划方程的边界
当p的起始字符(可能连续多个)为*时,由于*表示可以匹配任意字符或任意多个字符或空字符, 可以将其看作空字符,那么dp[i][0] = true, 其中i=[1, p.length()]
- 找出动态规划方程递推公式
1. p的第i个字符与s的第j个字符相同,或p的第i个字符为'?', '?'可以表示任意一个字符。 即p[i] == s[j] || p[i] == '?', 此时dp[i][j]的状态取决于他们前面的字符串是否匹配(因为当前已经匹配了),即dp[i][j] = dp[i-1][j-1]
2. p的第i个字符为'*', 由于*表示可以匹配任意字符或任意多个字符或空字符, 可以将其分为两种情况,使用这个'*'字符或不使用这个’*‘字符,当不使用’*‘字符时,dp[i][j] = dp[i-1][j], 即将p的第i个字符当成空字符。
当使用'*'字符时,只要p[i]与s的前j-1个字符中任意一个匹配,即可表示匹配(这表示的是s匹配的字符之后未匹配的字符用'*'来代替)。
import java.util.*; // 注意类名必须为 Main, 不要有任何 package xxx 信息 public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); // 注意 hasNext 和 hasNextLine 的区别 while (in.hasNextLine()) { // 注意 while 处理多个 case String p = in.nextLine(); String s = in.nextLine(); // 检验s中是否存在除字母和数字以外的字符 char[] arr_s = s.toCharArray(); for(int i=0;i<arr_s.length;i++){ char c = arr_s[i]; if(Character.isUpperCase(c)) arr_s[i] = Character.toLowerCase(c); } s = String.valueOf(arr_s); System.out.println(isMatch(p, s)); } } public static boolean isMatch(String p, String s){ int m = p.length(), n = s.length(); // dp[i][j]表示p的前i个字符是否能与s的前j个字符匹配 boolean[][] dp = new boolean[m+1][n+1]; // 初始化边界 dp[0][0] = true; // 空字符串可以匹配 for(int i=1;i<=m;i++){ if(p.charAt(i-1) == '*'){ // *可以匹配0个任意字符,当p的前面连续为*时,可以表示为不存在 dp[i][0] = true; }else{ break; } } for(int i=1;i<=m;i++){ char pc = p.charAt(i-1); if(Character.isUpperCase(pc)) pc = Character.toLowerCase(pc); for(int j=1;j<=n;j++){ char sc = s.charAt(j-1); if(pc == sc || (pc == '?' && (Character.isDigit(sc) || Character.isLetter(sc)))){ //当前字符与s中第j个字符相同 dp[i][j] = dp[i-1][j-1]; }else if(pc == '*'){ // 不使用'*',或 使用‘*’ // dp[i][j-1]是由 dp[i][0] || dp[i][1] ||... || dp[i][j-1]而来的, 而dp[i][j-2] 又是由dp[i][0] || ... ||dp[i][j-2]而来的, 所以此处直接可以由dp[i][j-1]递推而来 /* 该循环与下面的dp[i][j] = dp[i-1][j] || dp[i][j-1]是等价的,只不过使用该循环易于理解 for(int k=0;k<j;k++){ dp[i][j] = dp[i-1][j] || dp[i][k]; }*/ dp[i][j] = dp[i-1][j] || dp[i][j-1]; }else{ dp[i][j] = false; } } } return dp[m][n]; } }