第145题 字符串解压缩 | 豆包MarsCode AI刷题

103 阅读6分钟

image.png

这是一道经典的字符串问题,该问题要求我们将一个压缩后的字符串还原回原本的字符串。该问题的主要难度在于字符串的解析,下面就和我一起看下这个问题的解答过程吧。

问题描述

  1. 输入字符串是一种压缩形式:
    • 每个字母后面可能跟一个数字,该数字表示该字母在解压后需要重复的次数。
    • 如果一个字母后没有数字,则该字母在解压后只出现一次。
  2. 需要根据上述规则生成解压后的完整字符串。

分析规则

  1. 字母后面有数字:

    • 数字表示该字母的重复次数。
    • 如输入 "a2",解压结果为 "aa"
    • 如输入 "b3",解压结果为 "bbb"
  2. 字母后面无数字:

    • 默认情况下,字母只出现一次。
    • 如输入 "c",解压结果为 "c"
  3. 多位数字支持:

    • 如果一个字母后跟多位数字,如 "d12",需要将 12 解析为一个整体,表示字母 'd' 重复 12 次。
  4. 边界情况:

    • 空字符串输入时,输出也为空。
    • 不包含数字的字符串,如 "abc",输出为 "abc"

测试样例分析

示例 1:

输入:"a2b3c4"

解压过程:

  • 'a' 后面有 2:重复 2 次 → "aa"
  • 'b' 后面有 3:重复 3 次 → "bbb"
  • 'c' 后面有 4:重复 4 次 → "cccc"

最终结果:"aabbbcccc"

示例 2:

输入:"d5ef2"

解压过程:

  • 'd' 后面有 5:重复 5 次 → "ddddd"
  • 'e' 没有数字:重复 1 次 → "e"
  • 'f' 后面有 2:重复 2 次 → "ff"

最终结果:"dddddeff"

示例 3:

输入:"x3y1z"

解压过程:

  • 'x' 后面有 3:重复 3 次 → "xxx"
  • 'y' 后面有 1:重复 1 次 → "y"
  • 'z' 没有数字:重复 1 次 → "z"

最终结果:"xxxyz"

解题思路

  1. 遍历字符串:
    • 按顺序解析每个字符。
    • 判断该字符后是否有数字。
  2. 解析数字:
    • 如果有数字,则读取完整数字(支持多位)。
    • 如果没有数字,默认为 1
  3. 处理重复:
    • 根据解析的数字,将当前字母重复相应次数,并追加到结果字符串中。
  4. 跳过已解析部分:
    • 对于已经处理的字符和数字部分,直接跳过,继续解析下一个字符。

算法流程

  1. 初始化结果字符串 result 和索引变量 i
  2. 使用循环逐字符解析:
    • 当前字符为字母,将其保存。
    • 检查其后是否有数字,解析完整数字(如果存在)。
    • 按解析的数字将字母重复多次并追加到结果字符串中。
  3. 返回结果字符串。

边界条件

  1. 空输入:
    • 输入为空字符串时,直接返回空字符串。
  2. 无数字:
    • 如果所有字母后都没有数字,如 "abc",直接将字母拼接到结果。
  3. 多位数字:
    • 如果一个字母后有多位数字,如 "d123",需正确解析 123 并将 'd' 重复 123 次。
  4. 特殊字符:
    • 输入中不应包含非字母或数字的字符。如果包含,需要进一步处理异常。

代码实现

string solution(string s) {
    string result; // 存储解压后的字符串
    int i = 0;     // 当前索引

    while (i < s.length()) {
        char ch = s[i]; // 当前字符
        i++;
        int num = 0;
        int nonum = 1;
        // 检查字符后是否跟数字,并解析数字
        while (i < s.length() && isdigit(s[i])) {
            nonum = 0;
            num = num * 10 + (s[i] - '0');
            i++;
        }

        // 如果没有数字,默认重复 1 次
        if (nonum) {
            num = 1;
        }

        // 如果数字是 0,跳过当前字符
        if (num == 0 && !nonum) {
            continue;
        }

        // 将字符重复 num 次并添加到结果
        result.append(num, ch);
    }

    return result;
}

具体解析

1. 初始化变量

代码中初始化了以下变量:

  • result:用来存储最终解压后的字符串。
  • i:索引变量,用于遍历输入字符串 s
  • num:用于记录当前字母的重复次数。
  • nonum:一个辅助标志,用于判断当前字母后是否有数字。

通过这些变量的协作,我们能够实现对字符串的逐步解析,并根据规则正确处理每个字符及其重复次数。

2. 遍历字符串

while (i < s.length()) 循环保证我们可以逐字符地处理字符串的每一部分:

  • char ch = s[i];:获取当前字符并将索引 i 前移。
  • i++:向前移动索引以检查字符后是否存在数字。

3. 解析数字

在每次获取字符后,代码需要判断该字符后是否有数字:

  • 使用 isdigit(s[i]) 判断当前索引位置的字符是否为数字。
  • 如果是数字,将其转化为整数,更新变量 num

这一部分关键在于多位数字的处理。如果数字由多位组成,例如 d123,代码会通过 num = num * 10 + (s[i] - '0'); 累加解析所有数字。每次解析到一个数字,索引 i 继续向前移动,直到遇到非数字字符或字符串末尾。

4. 判断是否存在数字

为了处理字符后没有数字的情况,设置了 nonum 变量:

  • 初始值为 1,表示尚未遇到数字。
  • 如果进入 while (isdigit(s[i])) 循环,nonum 被设置为 0,表示当前字符后有数字。

在循环结束后,若 nonum 仍为 1,说明该字符后没有数字,按照规则设置 num = 1

5. 跳过无效字符

特殊情况是字符后数字为 0 的处理:

  • 如果 num == 0 && !nonum,说明数字明确为 0,此时直接跳过该字符,不将其添加到结果中。

这一逻辑确保了解压缩的正确性:字符后数字为 0 时应忽略该字符。

6. 生成解压结果

对于每个有效字符,代码使用 result.append(num, ch); 将字符重复 num 次添加到 result 中。string::append(size_t, char) 是 C++ STL 提供的高效方法,能够快速将字符多次添加到字符串末尾。

7. 返回结果

遍历完整个字符串后,函数返回 result,即解压缩后的字符串。

正确性分析

  1. 多位数字解析
    • 使用 num = num * 10 + (s[i] - '0') 能正确解析多位数字,例如 d123
    • 在循环中只处理连续数字部分,确保解析到的数字属于当前字符。
  2. 无数字处理
    • 辅助标志 nonum 确保能够正确处理无数字的字符,默认重复 1 次。
  3. 忽略 0 的字符
    • 当数字为 0 时跳过该字符,符合题目要求,保证结果正确。
  4. 边界条件
    • 字符串为空时,while 循环直接跳过,返回空字符串,符合预期。
    • 如果数字在字符串末尾,isdigit 判断能正确处理,无需额外校验。
  5. 时间复杂度
    • 每个字符和数字只遍历一次,因此时间复杂度为 (O(n)),适合大部分场景。

总结

这段代码通过高效的字符与数字解析逻辑,能够正确处理无数字、多位数字和数字为 0 的情况。时间复杂度 (O(n)) 和空间复杂度 (O(n)) 使其适用于大规模输入。代码逻辑清晰,功能完备,适合解压缩类似格式的字符串。