模板串匹配问题
模板串匹配问题是一类涉及字符串处理和组合生成的典型问题。下面本文将详细解析该问题的背景和解决思路,帮助大家深入理解这一类型问题的本质,并给出完整的解题过程。
问题描述
小U有一个特殊的"模板串",这个串由数字字符和问号?组成。通过将?替换为数字字符,小U可以生成许多正整数。但需要满足以下条件:
- 匹配出来的数字不能有前导零(如
012是不合法的)。 - 替换生成的所有数字按字典序排列后,小U需要找到其中第k小的结果。
- 如果不存在满足条件的第k小数字,则返回-1。
样例分析
让我们先通过几个具体例子直观理解问题。
样例1:
- 输入:
s = "??1",k = 1 - 输出:
101 - 分析:
?可以替换为数字0到9,生成的合法数字包括: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. 筛选有效结果
对于每一个生成的数字,我们需要判断它是否符合以下条件:
- 没有前导零(除非这个数字本身就是
0)。 - 是合法的正整数。
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函数部分
- 如果当前字符是
?,将其替换为0到9的所有数字,继续递归生成。 - 如果当前字符是固定的数字,则直接处理下一位。
- 当递归到字符串末尾时,检查生成的数字是否合法(例如没有前导零),并将其加入结果列表。
3. 回溯机制
- 在每次替换
?后,都需要恢复原状,这样才能继续生成其他组合。通过这一步操作,确保了递归的完整性。
时间和空间复杂度分析
1. 时间复杂度:
假设模板串中有n个?,每个?可以替换为10种数字,生成所有组合的复杂度为 。此外,排序复杂度为 。整体复杂度较高,但对于较短的模板串可以接受。
2. 空间复杂度:
结果列表的空间复杂度为。
总结与反思
1. 递归与回溯
- 本题的关键在于通过递归生成所有可能的结果,并结合回溯机制保证完整性。这是一种处理组合问题的通用方法。
2. 字典序排序与筛选
- 字典序排序是解决“第k小”问题的基础。但排序会增加时间复杂度,因此在实际应用中可以结合优先队列等数据结构进一步优化。
3. 实际应用场景
- 模板匹配问题在验证码生成、组合搜索等领域有广泛应用。通过这道题,我们可以熟悉这一类问题的思路,掌握递归、回溯、筛选的基本操作。
希望通过这篇文章,大家不仅能解决问题,还能掌握背后的思想方法!