A3→AAA类解压是运行长度编码(RLE)的简单解码,输入如"A3b2C1"输出"AAAbbC",数字仅作用于前一个字符;需遍历判断字母/数字、拼接多位数、避免越界和类型错误。
aaa)">
什么是 A3→AAA 这类解压?
这属于“运行长度编码”(RLE)的简单解码,不是 ZIP 或 GZIP 那种通用压缩。输入形如 "A3b2C1",输出是 "AAAbbC"。关键点在于:字符后紧跟数字(可能多位),且数字只作用于它前面的**一个字符**(不是前面所有字符)。常见错误是误以为 "AB3" 表示 "ABABAB",实际它不合法——按题意,数字必须紧贴单个字母。
用 std::string 遍历解析时怎么避免越界和类型转换错误?
核心是边扫边判断当前字符是字母还是数字。一旦遇到数字,就得把连续数字字符拼成整数(比如 '1' 和 '2' 要合成 12),再重复前一个字母。容易踩的坑:
- 没检查
i+1 < s.length()就访问s[i+1],导致越界崩溃 - 直接用
s[i] - '0'处理多位数,结果只取了最后一位("A12"变成重复 2 次) - 把数字字符当 ASCII 值直接用于循环次数,没转成
int
推荐做法:用 std::isdigit() 判断,配合 std::stoi() 或手写累加(更轻量):
std::string decompress(const std::string& s) {
std::string res;
for (size_t i = 0; i < s.length(); ++i) {
if (std::isalpha(s[i])) {
char c = s[i];
size_t j = i + 1;
// 找出后面连续的数字
while (j < s.length() && std::isdigit(s[j])) ++j;
if (j > i + 1) { // 确实有数字
int count = std::stoi(s.substr(i + 1, j - i - 1));
res.append(count, c);
i = j - 1; // 跳过已处理的数字
} else {
res += c; // 没数字,就加一次
}
}
}
return res;
}
为什么不用正则表达式(std::regex)?
理论上 std::regex 可以写成 R"((\D)(\d+))" 匹配“非数字+数字”,但实际中问题不少:
立即学习“C++免费学习笔记(深入)”;
-
std::regex在部分旧编译器(如 GCC 4.9、MSVC 2015)里实现不全或极慢 - 匹配过程需要反复构造
std::smatch,对短字符串(如"X5")开销反而比手写循环大 - 无法优雅处理末尾无数字的字符(如
"A3B"中的B),得额外补逻辑
除非你已在项目中重度依赖正则,否则纯遍历更稳、更快、更易调试。
输入含大小写、非字母字符时怎么处理?
题干说“A3→AAA”,但实际需求常要支持任意可打印字符(如空格、括号、数字本身)。这时不能只用 std::isalpha()。正确做法是:只要某个字符后面跟着数字,它就是被重复的“源字符”。所以应改为:
- 检测
s[i+1]是否为数字 → 那么s[i]就是待重复字符(无论它是字母、数字、符号甚至空格) - 但需排除一种情况:
s[i]是数字而s[i+1]也是数字(即数字串中间),此时s[i]不是源字符
更鲁棒的判断逻辑是:从左到右,每遇到一个数字,就往回找**最近的一个非数字字符**作为源字符。不过对于“字符紧邻数字”的约定(如 "A3" 合法,"13" 不合法),保持原遍历逻辑即可,只需把 std::isalpha() 换成 !std::isdigit()。
真正麻烦的是像 "123" 这种全数字输入——它没有定义明确的解压行为。实践中建议在函数开头加校验:if (s.empty() || std::all_of(s.begin(), s.end(), ::isdigit)) throw std::invalid_argument("no literal char found");,不然容易静默出错。


















