字符串匹配一例 | 豆包MarsCode AI刷题

3 阅读3分钟

字符串匹配一例 | 豆包MarsCode AI刷题

原题

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

方法一:python标准库 正则表达式

import re

def match_titles(n, template, titles):
    # 将模板中的通配符转换为正则表达式
    pattern = re.sub(r'\{.*?\}', '.*', template)
    
    # 编译正则表达式
    regex = re.compile(f'^{pattern}$')
    
    # 匹配标题
    results = []
    for title in titles:
        if regex.match(title):
            results.append("True")
        else:
            results.append("False")
    
    return ",".join(results)

方法二:自行实现

正则表达式当然爽,但是正则表达式是人实现的,那么我们怎么实现呢:

def solution(n, template, titles):

    # 解析模板

    parts = []

    i = 0

    while i < len(template):

        if template[i] == '{':

            j = i

            while j < len(template) and template[j] != '}':

                j += 1

            parts.append(template[i:j+1])

            i = j + 1

        else:

            j = i

            while j < len(template) and template[j] != '{':

                j += 1

            parts.append(template[i:j])

            i = j

    def match_title(template_parts, title):

        ti = 0

        for part in template_parts:

            if part.startswith('{') and part.endswith('}'):

                # 通配符部分,跳过

                continue

            else:

                # 固定部分,必须匹配

                part_len = len(part)

                while ti + part_len <= len(title) and title[ti:ti+part_len] != part:

                    ti += 1

                if ti + part_len > len(title):

                    return False

                ti += part_len

        return True

    results = []

    for title in titles:

        if match_title(parts, title):

            results.append("True")

        else:

            results.append("False")

    return ",".join(results)

看上去很对,但是其实遗漏了头和尾

没有考虑“一头一尾”,如:若第一个part位于template串首,最后一个part位于串尾,二者都不是通配的,那么,即便第一个part在title中匹配成功(并且即使是第一个匹配成功),但是如果匹配成功的位置不在title首部,而在中间,在模式匹配依然失败,尾部问题同理

改正如下,只要加上额外的判断即可

def solution(n, template, titles):

    # 解析模板

    parts = []

    i = 0

    while i < len(template):

        if template[i] == '{':

            j = i

            while j < len(template) and template[j] != '}':

                j += 1

            parts.append(template[i:j+1])

            i = j + 1

        else:

            j = i

            while j < len(template) and template[j] != '{':

                j += 1

            parts.append(template[i:j])

            i = j

    def match_title(template_parts, title):

        ti = 0

        # 处理首部

        if not template_parts[0].startswith('{'):

            part = template_parts[0]

            part_len = len(part)

            if title[:part_len] != part:

                return False

            ti += part_len

            template_parts = template_parts[1:]

        # 处理尾部

        if not template_parts[-1].startswith('{'):

            part = template_parts[-1]

            part_len = len(part)

            if title[-part_len:] != part:

                return False

            template_parts = template_parts[:-1]

        # 处理中间部分

        for part in template_parts:

            if part.startswith('{') and part.endswith('}'):

                # 通配符部分,跳过

                continue

            else:

                # 固定部分,必须匹配

                part_len = len(part)

                while ti + part_len <= len(title) and title[ti:ti+part_len] != part:

                    ti += 1

                if ti + part_len > len(title):

                    return False

                ti += part_len

        return True

    results = []

    for title in titles:

        if match_title(parts, title):

            results.append("True")

        else:

            results.append("False")

    return ",".join(results)

本题是并不困难的一个题目,主要是有一些细节值得注意。很多字符串/数组类型的问题都有类似的问题,也就是对于头和尾的特殊处理。另外关于正则表达式,确实是很有意思而且在脚本编写中非常重要的一个部分。关于如何正确的构造正则表达式事实上成为计算机学科中一个很有趣的小方向。比如有学者专门发文讨论如何写一个正则表达式能够匹配所有的电子邮件地址等。只能说计算机的水太深~