题目解析:模板串匹配问题| 豆包MarsCode AI 刷题

37 阅读4分钟

模板串匹配问题

模板串匹配问题是一类涉及字符串处理和组合生成的典型问题。下面本文将详细解析该问题的背景和解决思路,帮助大家深入理解这一类型问题的本质,并给出完整的解题过程。


问题描述

小U有一个特殊的"模板串",这个串由数字字符和问号组成。通过将替换为数字字符,小U可以生成许多正整数。但需要满足以下条件:

  1. 匹配出来的数字不能有前导零(如012是不合法的)。
  2. 替换生成的所有数字按字典序排列后,小U需要找到其中第k小的结果。
  3. 如果不存在满足条件的第k小数字,则返回-1。

样例分析

让我们先通过几个具体例子直观理解问题。

样例1:

  • 输入:s = "??1", k = 1
  • 输出:101
  • 分析
    可以替换为数字09,生成的合法数字包括:101, 111, 201...。其中第1小的是101

样例2:

  • 输入:s = "2??", k = 3
  • 输出:202
  • 分析
    替换后合法数字为:200, 201, 202, ...。按字典序排列,第3小的数字是202

样例3:

  • 输入:s = "000???", k = 1
  • 输出:-1
  • 分析
    任何替换后的结果都以000开头,这违反了“不能有前导零”的规则,因此没有符合条件的结果。

解题思路

为了解决这个问题,我们可以按照以下步骤展开:

1. 展开模板串

模板串中的是关键点,它可以被替换成任意数字。我们需要将所有可能的替换结果枚举出来。

2. 筛选有效结果

对于每一个生成的数字,我们需要判断它是否符合以下条件:

  1. 没有前导零(除非这个数字本身就是0)。
  2. 是合法的正整数。

3. 字典序排序

将筛选后的所有合法数字按字典序排序。

4. 查找第k小的数字

如果排序后的数字数量少于k,直接返回-1。否则返回第k小的数字。


代码实现

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Main {
    public static String solution(String s, int k) {
        List<String> results = new ArrayList<>();
        generateNumbers(s.toCharArray(), 0, results);
        Collections.sort(results);
        
        if (k > results.size()) {
            return "-1";
        }
        return results.get(k - 1);
    }

    private static void generateNumbers(char[] s, int index, List<String> results) {
        if (index == s.length) {
            String number = new String(s);
            if (!number.startsWith("0") || number.equals("0")) {
                results.add(number);
            }
            return;
        }

        if (s[index] == '?') {
            for (char c = '0'; c <= '9'; c++) {
                s[index] = c;
                generateNumbers(s, index + 1, results);
                s[index] = '?';
            }
        } else {
            generateNumbers(s, index + 1, results);
        }
    }

    public static void main(String[] args) {
        System.out.println(solution("??1", 1).equals("101"));
        System.out.println(solution("2??", 3).equals("202"));
        System.out.println(solution("000???", 1).equals("-1"));
    }
}

代码讲解

1. Main函数部分

  • 通过递归函数generateNumbers生成所有可能的结果。
  • 对结果列表按字典序排序。
  • 判断结果数量是否小于k,如果是则返回-1,否则返回第k小的数字。

2. generateNumbers函数部分

  • 如果当前字符是,将其替换为09的所有数字,继续递归生成。
  • 如果当前字符是固定的数字,则直接处理下一位。
  • 当递归到字符串末尾时,检查生成的数字是否合法(例如没有前导零),并将其加入结果列表。

3. 回溯机制

  • 在每次替换后,都需要恢复原状,这样才能继续生成其他组合。通过这一步操作,确保了递归的完整性。

时间和空间复杂度分析

1. 时间复杂度

假设模板串中有n个,每个可以替换为10种数字,生成所有组合的复杂度为 O(10n)O(10^n)。此外,排序复杂度为 O(10nlog(10n))O(10^n \log(10^n))。整体复杂度较高,但对于较短的模板串可以接受。

2. 空间复杂度

结果列表的空间复杂度为O(10n)O(10^n)


总结与反思

1. 递归与回溯

  • 本题的关键在于通过递归生成所有可能的结果,并结合回溯机制保证完整性。这是一种处理组合问题的通用方法。

2. 字典序排序与筛选

  • 字典序排序是解决“第k小”问题的基础。但排序会增加时间复杂度,因此在实际应用中可以结合优先队列等数据结构进一步优化。

3. 实际应用场景

  • 模板匹配问题在验证码生成、组合搜索等领域有广泛应用。通过这道题,我们可以熟悉这一类问题的思路,掌握递归、回溯、筛选的基本操作。

希望通过这篇文章,大家不仅能解决问题,还能掌握背后的思想方法!