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

97 阅读3分钟

问题描述

题目链接

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

    • 使用一个循环遍历模板字符串,遇到 { 时开始记录通配符部分,遇到 } 时结束记录。
    • 将非通配符部分和通配符部分分别存储在列表中。
  2. KMP 算法

    • 对于每个非通配符部分,生成 KMP 算法的 next 数组。
    • 在匹配过程中,使用 KMP 算法来高效地匹配非通配符部分。
  3. 匹配检查

    • 对于每个标题,依次匹配模板中的非通配符部分。
    • 如果所有非通配符部分都能匹配,则标题可以由模板生成。

代码实现

    public static String solution(int n, String template, String[] titles) {
        // Please write your code here
        String res = "";
        String temp = "";
        List<String> strS = new LinkedList<>();
        for (int i = 0; i < template.length(); i++) {
            if (template.charAt(i) == '{') {
                while (template.charAt(i) != '}') {
                    i++;
                }
                if (!temp.isEmpty()) {
                    strS.add(temp);
                    temp = "";
                }
            } else {
                temp = temp + template.charAt(i);
            }
        }
        if (!temp.isEmpty()) strS.add(temp);
        List<int []> nextS = new LinkedList<>();
        for (String str : strS) {
            int[] next = new int[str.length()];
            getNext(next, str);
            nextS.add(next);
        }

        for (String title : titles) {
            int len = title.length();
            int i = 0;
            int flag = 0;
            // 对每个title 用KMP算法进行字符串的匹配
            for (int k = 0; k < nextS.size(); k++) {
                int j = -1;
                String str = strS.get(k);
                int[] next = nextS.get(k);
                // 如果模版的最后一部分不是大括号,意味着模版与title的最后一部分一定要匹配,因此直接跳到最后一部分的匹配
                if (k == nextS.size() - 1 && template.charAt(template.length() - 1) != '}') {
                    i = len - str.length();
                }
                for ( ; i < len; i++) {
                    while (j >= 0 && str.charAt(j + 1) != title.charAt(i)) {
                        j = next[j];
                    }
                    if (title.charAt(i) == str.charAt(j + 1)) j++;
                    if (j == str.length() - 1) {
                        flag++;
                        i++;
                        break;
                    }
                }

            }
            if (flag == nextS.size()) {
                if (!res.isEmpty()) res += ",True";
                else res += "True";
            } else {
                if (!res.isEmpty()) res += ",False";
                else res += "False";
            }
        }
        return res;
    }

    public static void getNext(int[] next, String s) {
        int j  = -1;
        next[0] = j;
        for (int i = 1; i < s.length(); i++) {
            if (j >= 0 && s.charAt(i) != s.charAt(j + 1)) {
                j = next[j];
            }
            if (s.charAt(i) == s.charAt(j + 1)) j++;
            next[i] = j;
        }
    }

KMP算法的使用建议

KMP算法的核心思想是利用已经匹配的部分信息来避免不必要的回溯,从而提高匹配效率。它适用于在长文本中快速查找模式字符串。它通过预处理模式字符串生成部分匹配表(next数组),避免了在匹配失败时的大量重复比较,显著提升了匹配效率。KMP算法特别适合多次匹配或处理较长字符串的场景,例如文本编辑器中的查找功能、网络协议中字符串验证等。建议在需要频繁字符串匹配的程序中优先考虑使用KMP,以平衡时间复杂度和代码实现复杂度。而其实java中已经内置了寻找字符串子串的函数,也就是String类中的indexOf(),如果在非考试中使用时,可以直接使用封装函数来实现功能,Java 的indexOf在基础算法的基础上进行了高度优化。例如,它可能使用特定的字节编码优化(针对 UTF-16 的字符串),并直接调用 JVM 的本地方法进行实际的字符串匹配操作。