青训营X豆包MarsCode 刷题笔记 II |豆包MarsCode AI刷题

69 阅读4分钟

创意标题匹配问题刷题笔记


一、题目解析

问题描述
在广告平台中,允许广告主使用 {} 包含的通配符创建创意标题。通配符可以替换为任意字符,以生成用户触发的具体标题。给定一个含有通配符的模板字符串和多个待检测标题,需要判断每个标题是否可以通过通配符替换合法生成。

输入输出说明

  • 输入:

    1. n:标题个数。
    2. template:带通配符的模板字符串。
    3. titles:标题数组。
  • 输出:

    • 返回一个包含布尔值的字符串,表示每个标题是否符合模板生成的规则。

二、解题思路

  1. 模板解析

    • 将模板字符串中的固定部分提取出来(即不包含在 {} 中的部分)。
    • 使用一个辅助函数 getFixedStr 遍历模板,按顺序提取所有固定部分,忽略通配符内容。
  2. 逐标题匹配

    • 遍历每个标题,从左到右匹配提取的固定部分:

      • 如果固定部分按顺序完全匹配标题,则认为标题符合规则。
      • 匹配过程中,跳过通配符可能填充的任意字符。
  3. 边界处理

    • 模板中没有固定部分(全是通配符):所有标题均合法。
    • 标题长度不足以匹配所有固定部分:直接返回 False

三、代码实现

以下是完整代码以及注释:

import java.util.ArrayList;

public class Main {
    public static String solution(int n, String template, String[] titles) {
        // 将模板中的固定字符串部分提取出来
        ArrayList<String> tempList = getFixedStr(template);
        int clipsSize = 0; // 用于追踪匹配到的固定部分数量
        String clip = "";  // 当前正在匹配的固定部分
        String result = ""; // 最终结果字符串
        boolean endCheck = true; // 标记模板是否以固定部分结尾
        int tempLen = template.length();

        // 检查模板最后一个字符是否是通配符闭合符 '}'
        if (template.substring(tempLen - 1).compareTo("}") == 0) {
            endCheck = false; // 如果是通配符,固定部分不在最后
        }

        // 遍历每个标题
        for (int i = 0; i < n; i++) {
            clipsSize = 0; // 初始化当前标题的匹配固定部分计数
            int len = titles[i].length(); // 当前标题长度
            int j = 0; // 用于标题字符的逐步匹配

            while (j < len) {
                // 判断是否还有未匹配的固定部分
                if (clipsSize < tempList.size()) {
                    clip = tempList.get(clipsSize); // 获取当前需要匹配的固定部分
                }
                int clipLen = clip.length(); // 固定部分长度

                // 如果固定部分在模板结尾且当前是最后一部分
                if (endCheck && clipsSize + 1 == tempList.size()) {
                    // 检查标题最后的部分是否匹配固定部分
                    if (titles[i].substring(len - clipLen, len).compareTo(clip) == 0) {
                        clipsSize++; // 匹配成功,移动到下一部分
                    }
                    j = len; // 跳出循环
                }

                // 在标题中查找固定部分的位置
                if (j < len) {
                    if (j + clipLen <= len && titles[i].substring(j, j + clipLen).compareTo(clip) == 0) {
                        clipsSize++; // 匹配成功,移动到下一固定部分
                        j = j + clipLen; // 跳过匹配的固定部分
                    } else {
                        j++; // 未匹配时,移动标题指针
                    }
                }
            }

            // 将匹配结果追加到结果字符串中
            if (!result.isEmpty()) {
                result += ","; // 多个结果之间用逗号分隔
            }
            if (clipsSize == tempList.size()) {
                result += "True"; // 如果所有固定部分都匹配,则标题有效
            } else {
                result += "False"; // 否则标题无效
            }
        }
        return result; // 返回所有标题的匹配结果
    }

    public static ArrayList<String> getFixedStr(String template) {
        ArrayList<String> tmp = new ArrayList<String>(); // 用于存储固定部分
        int left = 0; // 用于记录固定部分的起始位置

        // 遍历模板字符串
        for (int i = 0; i < template.length(); i++) {
            if (template.charAt(i) == '{') {
                // 如果遇到通配符起始符,将之前的固定部分添加到结果中
                tmp.add(template.substring(left, i));
            } else if (template.charAt(i) == '}') {
                left = i + 1; // 跳过通配符部分
            }
        }
        // 添加最后的固定部分(如果有)
        if (left < template.length()) {
            tmp.add(template.substring(left, template.length()));
        }
        return tmp; // 返回所有固定部分
    }

    public static void main(String[] args) {
        // 测试样例
        String[] testTitles1 = { "adcdcefdfeffe", "adcdcefdfeff", "dcdcefdfeffe", "adcdcfe" };
        String[] testTitles2 = { "abcdefg", "abefg", "efg" };
        String[] testTitles3 = { "xyzdef", "abcdef", "abxyzdef", "xyz", "abxyz" };

        // 输出测试结果
        System.out.println(solution(4, "ad{xyz}cdc{y}f{x}e", testTitles1).equals("True,False,False,True"));
        System.out.println(solution(3, "a{bdc}efg", testTitles2).equals("True,True,False"));
        System.out.println(solution(5, "{abc}xyz{def}", testTitles3).equals("True,False,True,True,True"));
    }
}

四、知识总结

  1. 模板解析技巧

    • 将模板中的固定部分提取出来,存储为数组,简化匹配逻辑。
    • 通配符部分无需关心具体内容,仅需跳过即可。
  2. 匹配逻辑的优化

    • 按顺序匹配固定部分,避免对每个字符逐一检查。
    • 使用 substringindexOf 简化字符串的匹配逻辑。

五、个人总结

本题考察了模板解析和字符串匹配的综合能力。模板解析部分相对简单,但匹配逻辑对效率和正确性要求较高。通过合理分离模板的固定部分与通配符部分,可以更高效地解决类似问题。这种方法在广告、搜索推荐等领域有实际应用价值。