创意标题匹配问题刷题笔记
一、题目解析
问题描述
在广告平台中,允许广告主使用 {} 包含的通配符创建创意标题。通配符可以替换为任意字符,以生成用户触发的具体标题。给定一个含有通配符的模板字符串和多个待检测标题,需要判断每个标题是否可以通过通配符替换合法生成。
输入输出说明
-
输入:
- n:标题个数。
- template:带通配符的模板字符串。
- titles:标题数组。
-
输出:
- 返回一个包含布尔值的字符串,表示每个标题是否符合模板生成的规则。
二、解题思路
-
模板解析
- 将模板字符串中的固定部分提取出来(即不包含在
{}中的部分)。 - 使用一个辅助函数
getFixedStr遍历模板,按顺序提取所有固定部分,忽略通配符内容。
- 将模板字符串中的固定部分提取出来(即不包含在
-
逐标题匹配
-
遍历每个标题,从左到右匹配提取的固定部分:
- 如果固定部分按顺序完全匹配标题,则认为标题符合规则。
- 匹配过程中,跳过通配符可能填充的任意字符。
-
-
边界处理
- 模板中没有固定部分(全是通配符):所有标题均合法。
- 标题长度不足以匹配所有固定部分:直接返回
False。
三、代码实现
以下是完整代码以及注释:
import java.util.ArrayList;
public class Main {
public static String solution(int n, String template, String[] titles) {
// 将模板中的固定字符串部分提取出来
ArrayList<String> tempList = getFixedStr(template);
int clipsSize = 0; // 用于追踪匹配到的固定部分数量
String clip = ""; // 当前正在匹配的固定部分
String result = ""; // 最终结果字符串
boolean endCheck = true; // 标记模板是否以固定部分结尾
int tempLen = template.length();
// 检查模板最后一个字符是否是通配符闭合符 '}'
if (template.substring(tempLen - 1).compareTo("}") == 0) {
endCheck = false; // 如果是通配符,固定部分不在最后
}
// 遍历每个标题
for (int i = 0; i < n; i++) {
clipsSize = 0; // 初始化当前标题的匹配固定部分计数
int len = titles[i].length(); // 当前标题长度
int j = 0; // 用于标题字符的逐步匹配
while (j < len) {
// 判断是否还有未匹配的固定部分
if (clipsSize < tempList.size()) {
clip = tempList.get(clipsSize); // 获取当前需要匹配的固定部分
}
int clipLen = clip.length(); // 固定部分长度
// 如果固定部分在模板结尾且当前是最后一部分
if (endCheck && clipsSize + 1 == tempList.size()) {
// 检查标题最后的部分是否匹配固定部分
if (titles[i].substring(len - clipLen, len).compareTo(clip) == 0) {
clipsSize++; // 匹配成功,移动到下一部分
}
j = len; // 跳出循环
}
// 在标题中查找固定部分的位置
if (j < len) {
if (j + clipLen <= len && titles[i].substring(j, j + clipLen).compareTo(clip) == 0) {
clipsSize++; // 匹配成功,移动到下一固定部分
j = j + clipLen; // 跳过匹配的固定部分
} else {
j++; // 未匹配时,移动标题指针
}
}
}
// 将匹配结果追加到结果字符串中
if (!result.isEmpty()) {
result += ","; // 多个结果之间用逗号分隔
}
if (clipsSize == tempList.size()) {
result += "True"; // 如果所有固定部分都匹配,则标题有效
} else {
result += "False"; // 否则标题无效
}
}
return result; // 返回所有标题的匹配结果
}
public static ArrayList<String> getFixedStr(String template) {
ArrayList<String> tmp = new ArrayList<String>(); // 用于存储固定部分
int left = 0; // 用于记录固定部分的起始位置
// 遍历模板字符串
for (int i = 0; i < template.length(); i++) {
if (template.charAt(i) == '{') {
// 如果遇到通配符起始符,将之前的固定部分添加到结果中
tmp.add(template.substring(left, i));
} else if (template.charAt(i) == '}') {
left = i + 1; // 跳过通配符部分
}
}
// 添加最后的固定部分(如果有)
if (left < template.length()) {
tmp.add(template.substring(left, template.length()));
}
return tmp; // 返回所有固定部分
}
public static void main(String[] args) {
// 测试样例
String[] testTitles1 = { "adcdcefdfeffe", "adcdcefdfeff", "dcdcefdfeffe", "adcdcfe" };
String[] testTitles2 = { "abcdefg", "abefg", "efg" };
String[] testTitles3 = { "xyzdef", "abcdef", "abxyzdef", "xyz", "abxyz" };
// 输出测试结果
System.out.println(solution(4, "ad{xyz}cdc{y}f{x}e", testTitles1).equals("True,False,False,True"));
System.out.println(solution(3, "a{bdc}efg", testTitles2).equals("True,True,False"));
System.out.println(solution(5, "{abc}xyz{def}", testTitles3).equals("True,False,True,True,True"));
}
}
四、知识总结
-
模板解析技巧
- 将模板中的固定部分提取出来,存储为数组,简化匹配逻辑。
- 通配符部分无需关心具体内容,仅需跳过即可。
-
匹配逻辑的优化
- 按顺序匹配固定部分,避免对每个字符逐一检查。
- 使用
substring和indexOf简化字符串的匹配逻辑。
五、个人总结
本题考察了模板解析和字符串匹配的综合能力。模板解析部分相对简单,但匹配逻辑对效率和正确性要求较高。通过合理分离模板的固定部分与通配符部分,可以更高效地解决类似问题。这种方法在广告、搜索推荐等领域有实际应用价值。