问题描述
在广告平台中,为了给广告主一定的自由性和效率,允许广告主在创造标题的时候以通配符的方式进行创意提交。线上服务的时候,会根据用户的搜索词触发的 bidword 对创意中的通配符(通配符是用成对 {} 括起来的字符串,可以包含 0 个或者多个字符)进行替换,用来提升广告投放体验。例如:“{末日血战} 上线送 SSR 英雄,三天集齐无敌阵容!”,会被替换成“帝国时代游戏下载上线送 SSR 英雄,三天集齐无敌阵容!”。给定一个含有通配符的创意和n个标题,判断这句标题是否从该创意替换生成的。
测试样例
样例1:
输入:
n = 4, template = "ad{xyz}cdc{y}f{x}e", titles = ["adcdcefdfeffe", "adcdcefdfeff", "dcdcefdfeffe", "adcdcfe"]
输出:"True,False,False,True"
样例2:
输入:
n = 3, template = "a{bdc}efg", titles = ["abcdefg", "abefg", "efg"]
输出:"True,True,False"
样例3:
输入:
n = 5, template = "{abc}xyz{def}", titles = ["xyzdef", "abcdef", "abxyzdef", "xyz", "abxyz"]
输出:"True,False,True,True,True"
解决思路
-
模板解析:
- 使用一个循环遍历模板字符串,遇到
{时开始记录通配符部分,遇到}时结束记录。 - 将非通配符部分和通配符部分分别存储在列表中。
- 使用一个循环遍历模板字符串,遇到
-
KMP 算法:
- 对于每个非通配符部分,生成 KMP 算法的 next 数组。
- 在匹配过程中,使用 KMP 算法来高效地匹配非通配符部分。
-
匹配检查:
- 对于每个标题,依次匹配模板中的非通配符部分。
- 如果所有非通配符部分都能匹配,则标题可以由模板生成。
代码实现
public static String solution(int n, String template, String[] titles) {
// Please write your code here
String res = "";
String temp = "";
List<String> strS = new LinkedList<>();
for (int i = 0; i < template.length(); i++) {
if (template.charAt(i) == '{') {
while (template.charAt(i) != '}') {
i++;
}
if (!temp.isEmpty()) {
strS.add(temp);
temp = "";
}
} else {
temp = temp + template.charAt(i);
}
}
if (!temp.isEmpty()) strS.add(temp);
List<int []> nextS = new LinkedList<>();
for (String str : strS) {
int[] next = new int[str.length()];
getNext(next, str);
nextS.add(next);
}
for (String title : titles) {
int len = title.length();
int i = 0;
int flag = 0;
// 对每个title 用KMP算法进行字符串的匹配
for (int k = 0; k < nextS.size(); k++) {
int j = -1;
String str = strS.get(k);
int[] next = nextS.get(k);
// 如果模版的最后一部分不是大括号,意味着模版与title的最后一部分一定要匹配,因此直接跳到最后一部分的匹配
if (k == nextS.size() - 1 && template.charAt(template.length() - 1) != '}') {
i = len - str.length();
}
for ( ; i < len; i++) {
while (j >= 0 && str.charAt(j + 1) != title.charAt(i)) {
j = next[j];
}
if (title.charAt(i) == str.charAt(j + 1)) j++;
if (j == str.length() - 1) {
flag++;
i++;
break;
}
}
}
if (flag == nextS.size()) {
if (!res.isEmpty()) res += ",True";
else res += "True";
} else {
if (!res.isEmpty()) res += ",False";
else res += "False";
}
}
return res;
}
public static void getNext(int[] next, String s) {
int j = -1;
next[0] = j;
for (int i = 1; i < s.length(); i++) {
if (j >= 0 && s.charAt(i) != s.charAt(j + 1)) {
j = next[j];
}
if (s.charAt(i) == s.charAt(j + 1)) j++;
next[i] = j;
}
}
KMP算法的使用建议
KMP算法的核心思想是利用已经匹配的部分信息来避免不必要的回溯,从而提高匹配效率。它适用于在长文本中快速查找模式字符串。它通过预处理模式字符串生成部分匹配表(next数组),避免了在匹配失败时的大量重复比较,显著提升了匹配效率。KMP算法特别适合多次匹配或处理较长字符串的场景,例如文本编辑器中的查找功能、网络协议中字符串验证等。建议在需要频繁字符串匹配的程序中优先考虑使用KMP,以平衡时间复杂度和代码实现复杂度。而其实java中已经内置了寻找字符串子串的函数,也就是String类中的indexOf(),如果在非考试中使用时,可以直接使用封装函数来实现功能,Java 的indexOf在基础算法的基础上进行了高度优化。例如,它可能使用特定的字节编码优化(针对 UTF-16 的字符串),并直接调用 JVM 的本地方法进行实际的字符串匹配操作。