简单题:创意标题匹配问题

104 阅读5分钟

问题描述

在广告平台中,为了给广告主一定的自由性和效率,允许广告主在创造标题的时候以通配符的方式进行创意提交。线上服务的时候,会根据用户的搜索词触发的 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"

代码解析:

这段代码的主要功能是判断给定的标题列表是否与模板匹配。模板中可以使用 {...} 表示通配符,可以匹配任意长度的字符串(包括空字符串)。

代码的核心逻辑在于 match_template 函数中的 backtrack 递归函数。该函数通过回溯法遍历模板和标题的所有可能匹配情况,并判断是否能够完全匹配。

代码注释:

代码中已经添加了详细的注释,解释了每个函数和代码块的功能、参数和返回值,以及关键的逻辑判断。

主要步骤:

  1. 遍历标题列表: 代码首先遍历 titles 列表中的每个标题。

  2. 匹配模板: 对于每个标题,调用 match_template 函数判断其是否与模板匹配。

  3. 回溯匹配: match_template 函数中使用 backtrack 递归函数进行回溯匹配。

    • 基本情况: 如果模板和标题都到达末尾,则匹配成功。如果模板到达末尾但标题没有匹配完,或标题到达末尾但模板未匹配完,则匹配失败。
    • 通配符匹配: 如果遇到 {,则寻找匹配的 },并跳过 {...} 内的内容。然后,尝试将通配符与标题中任意长度的字符串进行匹配,并递归判断剩余部分是否匹配。
    • 普通字符匹配: 如果当前字符不是 {,则将其与标题中的对应字符进行比较。如果匹配,则继续递归匹配下一个字符;否则,匹配失败。
  4. 记录结果: 将每个标题的匹配结果存储在 results 列表中。

  5. 返回结果:results 列表转换为逗号分隔的字符串并返回。

示例:

例如,对于模板 "a{bdc}efg" 和标题 "abcdefg"backtrack 函数的执行过程如下:

  1. 初始状态:i = 0j = 0
  2. 匹配 atemplate[0] == title[0]ij 分别加 1。
  3. 遇到 {:寻找 }i 变为 5。
  4. 通配符匹配:尝试将 "{bdc}""bcdef""cdef""def""ef""f""" 进行匹配。
  5. 递归匹配:当 "{bdc}" 匹配 "bcd" 时,递归调用 backtrack(5, 3),继续匹配剩余部分。
  6. 最终匹配成功:ij 都到达末尾。
def solution(n, template_, titles):
    '''
    这个函数用于判断多个标题是否与给定的模板匹配。

    参数:
        n: 标题的数量 (int)
        template_: 模板字符串 (str)
        titles: 标题列表 (list of str)

    返回值:
        一个逗号分隔的字符串,表示每个标题是否与模板匹配 (str)
        例如: "True,False,True"
    '''

    def match_template(template, title):
        '''
        这个函数使用回溯法判断单个标题是否与模板匹配。

        参数:
            template: 模板字符串 (str)
            title: 标题字符串 (str)

        返回值:
            如果标题与模板匹配,则返回 True,否则返回 False (bool)
        '''

        def backtrack(i, j):
            '''
            这是一个递归函数,用于在模板和标题中进行回溯匹配。

            参数:
                i: 当前在模板字符串中的索引 (int)
                j: 当前在标题字符串中的索引 (int)

            返回值:
                如果从当前索引开始可以匹配成功,则返回 True,否则返回 False (bool)
            '''

            # 如果模板和标题都到达末尾,则匹配成功
            if i == len(template) and j == len(title):
                return True
            # 如果模板到达末尾但标题没有匹配完,或标题到达末尾但模板未匹配完,则匹配失败
            if i == len(template) or j > len(title):  # 注意这里 j > len(title) 是允许的,因为通配符可以匹配空字符串
                return False

            # 如果遇到 '{',则寻找匹配的 '}'
            if template[i] == '{':
                end = i + 1
                while end < len(template) and template[end] != '}':
                    end += 1
                # 获取 `{...}` 内的内容并跳过
                i = end + 1

                # 通配符匹配标题中任意长度的字符串
                for k in range(j, len(title) + 1):  # 注意 k 可以取到 len(title),表示匹配空字符串
                    if backtrack(i, k):  # 递归判断从 k 开始匹配
                        return True
                return False  # 如果所有可能的 k 都无法匹配,则返回 False
            else:
                # 普通字符精确匹配
                if j < len(title) and template[i] == title[j]:
                    return backtrack(i + 1, j + 1)
                return False  # 如果当前字符不匹配,则返回 False

        return backtrack(0, 0)  # 从模板和标题的开头开始匹配

    results = []
    for title in titles:
        if match_template(template_, title):
            results.append("True")
        else:
            results.append("False")

    return ",".join(results)  # 将结果转换为逗号分隔的字符串


# 测试代码
if __name__ == "__main__":
    testTitles1 = ["adcdcefdfeffe", "adcdcefdfeff", "dcdcefdfeffe", "adcdcfe"]
    testTitles2 = ["abcdefg", "abefg", "efg"]
    testTitles3 = ["xyzdef", "abcdef", "abxyzdef", "xyz", "abxyz"]

    print(solution(4, "ad{xyz}cdc{y}f{x}e", testTitles1))  # Expected: "True,False,False,True"
    print(solution(3, "a{bdc}efg", testTitles2))  # Expected: "True,True,False"
    print(solution(5, "{abc}xyz{def}", testTitles3))  # Expected: "True,False,True,True,True"