问题描述
小D拿到了一个仅由 "abc" 三种字母组成的字符串。她每次操作会对所有字符同时进行以下变换
- 将 'a' 变成 'bc'
- 将 'b' 变成 'ca'
- 将 'c' 变成 'ab'
小D将重复该操作 k 次。你的任务是输出经过 k 次变换后,得到的最终字符串。 例如:对于初始字符串 "abc",执行 2 次操作后,字符串将变为 "caababbcbcca"。
测试样例
- 样例1: 输入:s = "abc", k = 2 输出:'caababbcbcca'
- 样例2: 输入:s = "abca", k = 3 输出:'abbcbccabccacaabcaababbcabbcbcca'
- 样例3: 输入:s = "cba", k = 1 输出:'abcabc'
问题分析
从题面上我们很容易想到使用模拟的方式进行解答。
string solution(string s, int k) {
// 定义字符的变换规则
std::unordered_map<char, std::string> transformation = {
{'a', "bc"},
{'b', "ca"},
{'c', "ab"}
};
std::string current = s;
// 进行 k 次变换
for (int i = 0; i < k; ++i) {
std::string new_string;
for (char c : current) {
new_string += transformation[c]; // 根据规则替换每个字符
}
current = new_string; // 更新当前字符串
}
return current;
}
int main() {
cout << (solution("abc", 2) == "caababbcbcca") << endl;
cout << (solution("abca", 3) == "abbcbccabccacaabcaababbcabbcbcca") << endl;
cout << (solution("cba", 1) == "abcabc") << endl;
return 0;
}
但是不难发现字符串在每次操作后长度成指数级增长,复杂度较高,只适合小数值计算。
一种优化方法是分析变换的规律,找到变换的周期性或规律,然后利用这一规律直接计算出第 k次变换后的结果,而不必每次都生成完整的中间字符串。
观察变换的规律:
通过几次手动变换,我们可以发现以下规律:
每个字符经过几次变换后会形成一个固定的子串模式。 这种模式在进一步变换时保持不变,只是长度会随着变换次数增大。 例如:
'a' 经过 1 次变换变成 'bc',再经过 1 次变换变成 'caab',继续变换后会形成更长的字符串,但内容上会遵循某种固定模式。
'b' 和 'c' 也类似。
动态生成变换序列:
我们可以用一个递归或动态生成的方式,针对每个初始字符直接生成第 k 次的变换结果。以下是优化后的 C++ 代码:
#include <iostream>
#include <string>
#include <unordered_map>
using namespace std;
std::unordered_map<char, std::unordered_map<int, std::string>> memo;
std::string transform(char c, int k) {
if (k == 0) return std::string(1, c);
// 如果已经计算过,则直接返回缓存的结果
if (memo[c].count(k)) return memo[c][k];
std::string result;
if (c == 'a') {
result = transform('b', k - 1) + transform('c', k - 1);
} else if (c == 'b') {
result = transform('c', k - 1) + transform('a', k - 1);
} else if (c == 'c') {
result = transform('a', k - 1) + transform('b', k - 1);
}
// 缓存计算结果
memo[c][k] = result;
return result;
}
std::string solution(const std::string& s, int k) {
std::string result;
for (char c : s) {
result += transform(c, k);
}
return result;
}
int main() {
cout << (solution("abc", 2) == "caababbcbcca") << endl;
cout << (solution("abca", 3) == "abbcbccabccacaabcaababbcabbcbcca") << endl;
cout << (solution("cba", 1) == "abcabc") << endl;
return 0;
}
代码解释
使用一个 memo 哈希表缓存 transform(c, k) 的结果,避免重复计算。这显著减少了递归调用的次数。
transform 函数递归计算字符 c 在经过 k 次变换后的字符串,通过直接递归地构建字符串而不是一步步变换,降低了时间复杂度。
每个字符只计算一遍,且通过缓存减少了冗余计算。