284.模板串匹配问题 | 豆包MarsCode AI刷题

95 阅读3分钟

问题回顾

目标: 从包含数字和问号(?)的字符串 s 中,生成可替换为正整数的形式,并找出字典序中第 k 小的正整数。若不存在这样的第 k 小正整数,则返回 -1

重点:

  1. 字符串中的 ? 要替换为数字(0-9)。
  2. 替换后的结果需为正整数,不能有前导零。
  3. 按字典顺序顺序查找第 k 小的结果。

代码思路

1. 初始化

在代码的最开始部分,我们定义了一个空字符串 t,用于存储在处理过程中需要的临时答案。接下来的 for 循环用于遍历字符串 s

string t = "";
for (char ch : s) {
    if (ch == '?') t += '0'; // 将?预先替换为0
}
  • 遍历 s,若当前字符是 ?,则在 t 中相应位置填入 0

2. 处理首位的 ?

接着,我们需要特殊处理字符串的第一位:

if (s[0] == '?') t[0] = '1'; // 如果首位为?,那么其必须至少为1
  • 如果字符串的第一位是 ?,它必须至少为 1,以避免生成的数字出现前导零。

3. 调整 k 值

之后我们将 k 减 1,因为数组索引通常是从 0 开始,我们需要在处理时将 k 转换为基于零的索引:

k--; // 调整 k,从0开始

4. 判断是否可以生成有效数字

在生成第 k 小数字之前,我们需要确保 k 是有效的。如果 k 超出了可能生成的数字范围,则直接返回 -1

string sk = to_string(k);
if (sk.size() > t.size() || (sk.size() == t.size() && t[0] - '0' + sk[0] - '0' > 9)) {
    return "-1"; // k 超出可产生数字的范围
}
  • sk.size() > t.size() 检查是否 k 的位数超出了字符串 t,因为这意味着没有足够的数字来表示 k。
  • 第二个条件用于确保即使在位数相同的情况下,k 也不能导致生成的数字有前导零。

5. 计算第 k 小的数字

在确定 k 是有效的后,接下来我们需要从字符串 t 中生成第 k 小的数字。我们从 sk(将 k 转换为字符串后)开始,进行逐位加法:

int n = t.size();
int m = sk.size();

// 从后往前进行数字填充
for (int i = m - 1, j = n - 1; i >= 0; --i, --j) {
    t[j] += sk[i] - '0'; // 将 k 的每一位加到 t 中
}
  • 将字符串 sk 从后往前一位一位加到 t 中。通过这个步骤,我们确保了形成的数字是字典序中第 k 小的那一个。

6. 输出生成的结果

最后,我们需要根据 s 中的 ? 替换相应的数字,并进行最终的校验:

int now = 0;
string ans;
for (char ch : s) {
    if (ch == '?') {
        ans += t[now++]; // 用 t 中的数字替换 ?
    } else {
        ans += ch; // 直接加上原字符
    }
}

if (ans.size() > 1 && ans[0] == '0') return "-1"; // 检查是否有前导零
return ans;
  • 在这个循环中,对于每个字符,如果是 ?,则替换为字符串 t 中相应的数字;如果是原字符,直接加到结果中。
  • 最后再检查一下如果结果字符串的长度超过 1 且其首位是 0,则返回 -1 防止前导零。

总结

这段代码的整体思路是通过对 ? 的合理替换来构造出需要的数字,从而找到字典序中第 k 小的正整数。代码的核心在于精确处理 ? 的替换以及控制前导零,同时通过对 k 的巧妙利用来避免生成其他不必要的数字,保证了算法的高效性。

这种方法效率高,适用于大小适中的输入字符串,确保在允许范围内计算出有效的正整数,同时考虑了各种边角情况,能够在保证正确性的基础上返回准确的结果。