Python解决“创意标题匹配”问题

Python解决“创意标题匹配”问题

问题描述

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

解题思路

题目要求判断给定的标题是否可以从含有通配符的模板中生成。模板中的通配符用成对的花括号 {} 括起来,可以包含任意字符。我们需要检查每个标题是否符合模板的要求,即标题中的非通配符部分必须与模板中的非通配符部分完全匹配,并且通配符部分可以被任意字符替换。

为了解决这个问题,我们可以将模板分为三部分:模板的前缀(在第一个通配符之前的部分)、模板的后缀(在最后一个通配符之后的部分)以及模板中的通配符部分。然后,我们使用正则表达式提取出模板中的非通配符部分,并检查每个标题是否符合这些部分的顺序和内容。

解题过程为:

  1. 提取模板的前缀和后缀:
  • 找到模板中第一个通配符 { 的位置 p 和最后一个通配符 }的位置 q
  • 提取模板的前缀 sttemplate_[:p],后缀 edtemplate_[q+1:]
  1. 提取模板中的非通配符部分:
  • 使用正则表达式 re.findall(r'[^{}]+(?=\{)|(?<=\})[^{}]+|^[^{]+|[^}]+$', template_) 提取模板中的非通配符部分 subs
  1. 检查标题是否符合模板:
  • 对于每个标题 s,首先检查其长度是否至少为 len(st) + len(ed),并且是否以 st 开头,以 ed 结尾。
  • 然后,遍历 subs中的每个非通配符部分 t,检查 s 中是否包含 t,并且 ts 中的位置是否符合顺序。
  1. 返回结果:
  • 将每个标题的检查结果转换为字符串,并用逗号连接,返回最终结果。

时间复杂度:
提取模板的前缀和后缀的时间复杂度为 O(n),其中 n 是模板的长度。
使用正则表达式提取非通配符部分的时间复杂度为 O(n)。
对于每个标题,检查其是否符合模板的时间复杂度为 O(m),其中 m 是标题的长度。
因此,总的时间复杂度为 O(n+m⋅k),其中 k 是标题的数量。

空间复杂度:
存储模板的前缀、后缀和非通配符部分的空间复杂度为 O(n)。
因此,总的空间复杂度为 O(n)。

代码

import re

def solution(n: int, template_: str, titles: list) -> str:
    # 确保输入的标题数量与 n 一致
    assert n == len(titles)
    
    # 如果模板中没有通配符,直接比较模板和每个标题是否相等
    if "{" not in template_:
        return [template_ == s for s in titles]
    
    # 找到模板中第一个和最后一个通配符的位置
    p, q = template_.find('{'), template_.rfind('}')
    
    # 提取模板中通配符前后的固定部分
    st, ed = template_[:p], template_[q + 1:]
    
    # 提取模板中包含通配符的部分
    template_ = template_[p:q + 1]
    
    # 使用正则表达式提取模板中的固定部分(非通配符部分)
    subs = re.findall(r'[^{}]+(?=\{)|(?<=\})[^{}]+|^[^{]+|[^}]+$', template_)
    # print(subs)

    # 定义一个函数来检查标题是否符合模板
    # s是一个变量,用于表示每个标题字符串。
    def ok(subs, s: str):
        # 标题的长度必须至少为固定部分的长度之和,并且以 st 开头,以 ed 结尾
        if not (len(s) >= len(st) + len(ed) and s.startswith(st) and s.endswith(ed)):
            return False
        
        p = 0 # 函数使用一个指针 p 来跟踪当前检查的位置。
        # 检查标题中是否包含所有固定部分
        for t in subs:
            q = s.find(t, p) # 找到则返回位置,找不到则返回-1
            if q == -1:
                return False
            p = q + len(t) # 跟新了指针 p 的位置 接着之后找
        return True

    # 对每个标题调用 ok 函数,并将结果转换为字符串列表
    return ','.join(map(str, [ok(subs, s) for s in titles]))
    # map 函数将一个函数(在这里是 str 函数)应用到一个可迭代对象(在这里是列表推导式生成的布尔值列表)的每一个元素上。
    # join 方法将一个可迭代对象(在这里是 map 函数生成的字符串列表)中的所有元素连接成一个字符串。

if __name__ == '__main__':
    # 测试样例1
    print(solution(n=4, template_="ad{xyz}cdc{y}f{x}e", titles=[
          "adcdcefdfeffe", "adcdcefdfeff", "dcdcefdfeffe", "adcdcfe"]) == "True,False,False,True")
    
    # 测试样例2
    print(solution(n=3, template_="a{bdc}efg", titles=[
          "abcdefg", "abefg", "efg"]) == "True,True,False")
    
    # 测试样例3
    print(solution(n=5, template_="{abc}xyz{def}", titles=[
        "xyzdef", "abcdef", "abxyzdef", "xyz", "abxyz"]) == "True,False,True,True,True")

输出:
True
True
True

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

啥都鼓捣的小yao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值