创意标题匹配问题 | 豆包MarsCode AI刷题

251 阅读4分钟

创意标题匹配问题

问题描述

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

解析模板,将固定部分和通配符分开:

  1. 固定部分:ad
  2. 通配符:{xyz}
  3. 固定部分:cdc
  4. 通配符:{y}
  5. 固定部分:f
  6. 通配符:{x}
  7. 固定部分:e

因此,模板可以表示为:

ad + {xyz} + cdc + {y} + f + {x} + e

我们需要为每个标题判断是否存在一种替换,使得替换后的字符串等于标题。

逐个分析标题:

标题1: "adcdcefdfeffe"

  1. 固定部分ad匹配标题的前两个字符ad
  2. 寻找固定部分cdc,在标题中位置2开始匹配,发现cdc匹配标题的第3-5个字符cdc
  3. 接下来固定部分f需要匹配标题中的某个位置。假设通配符{y}替换为e,则固定部分f匹配标题的第7个字符f
  4. 最后固定部分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)