创意标题匹配问题
问题描述
在广告平台中,为了给广告主一定的自由性和效率,允许广告主在创造标题的时候以通配符的方式进行创意提交。线上服务的时候,会根据用户的搜索词触发的 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"
题目解读:
题目要求判断给定的标题是否可以通过替换模板中的通配符生成。模板中固定的部分必须和标题中的相应部分严格匹配,通配符可以替换为任意字符串(包括空字符串)。
模板解析:
模板为:"ad{xyz}cdc{y}f{x}e"
解析模板,将固定部分和通配符分开:
- 固定部分:
ad - 通配符:
{xyz} - 固定部分:
cdc - 通配符:
{y} - 固定部分:
f - 通配符:
{x} - 固定部分:
e
因此,模板可以表示为:
ad + {xyz} + cdc + {y} + f + {x} + e
我们需要为每个标题判断是否存在一种替换,使得替换后的字符串等于标题。
逐个分析标题:
标题1: "adcdcefdfeffe"
- 固定部分
ad匹配标题的前两个字符ad。 - 寻找固定部分
cdc,在标题中位置2开始匹配,发现cdc匹配标题的第3-5个字符cdc。 - 接下来固定部分
f需要匹配标题中的某个位置。假设通配符{y}替换为e,则固定部分f匹配标题的第7个字符f。 - 最后固定部分
e需要匹配标题的最后一个字符e。
经过上述匹配,通配符替换为:
{xyz}替换为(空字符串){y}替换为e{x}替换为dfeff
因此,标题1可以通过模板生成,输出True。
标题2: "adcdcefdfeff"
按照类似的方法进行匹配,最后发现固定部分e需要匹配标题的最后一个字符,但是标题最后一个字符是f,不匹配。因此,标题2无法通过模板生成,输出False。
标题3: "dcdcefdfeffe"
模板的第一个固定部分是ad,但标题的前两个字符是dc,不匹配。因此,标题3无法通过模板生成,输出False。
标题4: "adcdcfe"
固定部分和标题完全匹配,所有通配符替换为空字符串即可。因此,标题4可以通过模板生成,输出True。
总结:
- 标题1:匹配成功,输出
True - 标题2:匹配失败,输出
False - 标题3:匹配失败,输出
False - 标题4:匹配成功,输出
True
解题思路
这个题就是一个字符串匹配问题。常用的解决方法就是使用正则表达式。
正则表达式在java和python中都有,具体的语法不同,但是实现思想和步骤基本都是一样的:
Python Code
def solution(n, template_, titles):
# 使用python的正则表达式匹配做。
regex_pattern = '' # 初始化正则表达式模式】
i = 0 # 遍历索引
while i < len(template_):
if template_[i] == '{': # 遇到{认为遇到通配符,一直找到最后的}
i+=1
while i < len(template_) and template_[i] != '}':
i += 1
regex_pattern += '.*' #将通配符转为任意匹配的字符串。 .表示匹配任意字符串。*表示匹配零次或多次
else:
regex_pattern += re.escape(template_[i]) # 如果不是通配符,需要完全匹配上。直接先 转义,并将其加入到正则表达式模板中
i += 1
# 使用正则表达式进行匹配
regex = re.compile(f'^{regex_pattern}$') # 全匹配
results = [bool(regex.match(title)) for title in titles]
# 将 results列表转换为逗号分隔的字符串
# str 函数将布尔值转换为字符串,因此 map(str, results) 的结果是一个字符串列表,例如 ["True", "False", "True"]
# ','.join(...) 是字符串的 join 方法,它将一个可迭代对象(例如列表)中的所有元素连接成一个字符串,并用指定的分隔符(在这里是逗号 ,)分隔。
results_str = ','.join(map(str, results))
return results_str
Java Code
public static String solution(int n, String template, String[] titles) {
// 初始化正则表达式模式
StringBuilder regexPattern = new StringBuilder();
int i = 0;
while (i < template.length()) {
if (template.charAt(i) == '{') {
// 遇到{认为遇到通配符,一直找到最后的}
i++;
while (i < template.length() && template.charAt(i) != '}') {
i++;
}
regexPattern.append(".*"); // 将通配符转为任意匹配的字符串
} else {
// 如果不是通配符,需要完全匹配上。直接先转义,并将其加入到正则表达式模板中
regexPattern.append(Pattern.quote(String.valueOf(template.charAt(i)))); // Pattern.quote用于将字符串转为正则表达式字面量,通常是处理特殊字符如 . * ? [ ]
}
i++;
}
// 使用正则表达式进行匹配
Pattern regex = Pattern.compile("^" + regexPattern.toString() + "$"); // 全匹配
List<String> results = new ArrayList<>();
for (String title : titles) {
Matcher matcher = regex.matcher(title);
// 如果能够匹配成功,matcher.matches()返回true。反之返回false。
results.add(matcher.matches() ? "True" : "False");
}
// 将 results 列表转换为逗号分隔的字符串
return String.join(",", results);
}
刷后感
感觉这个题的含金量并不是很大, 就是考察对正则表达式的理解以及对正则表达式语法的使用。不过忘记就真的完蛋了(bushi)