面试知识库

394. 字符串解码#

今天我们来探讨一道非常有趣的算法题 - LeetCode 394「字符串解码」。这道题考察了栈和递归的灵活运用,是一道非常能锻炼编程思维的好题目。

📚 从生活场景理解#

想象你正在开发一个文本压缩软件。比如要表达”hellohellobello”,与其写三遍,我们可以写成”3[hello]“来节省空间。如果字符串中还包含重复的部分,可以继续嵌套压缩,这就是今天要解决的问题!

问题描述#

题目目标#

给定一个经过编码的字符串 s ,按照规则 k[encoded_string] 进行解码并返回结果,其中方括号内的字符串会被重复 k 次。输入保证格式合法,且不会出现额外空格。

示例 1#

输入: s = "3[a]2[bc]" 输出: "aaabcbc" 说明: 把输入和输出放在一起看,会更容易直接抓住题目要求的变化。

💡 问题解析#

题目要求: 给定一个经过编码的字符串,返回它解码后的字符串。编码规则是:

  1. k[encoded_string] 表示 encoded_string 重复 k 次
  2. encoded_string 里可能包含更多的方括号结构
  3. 数字 k 保证为正整数

示例:

输入:s = "3[a]2[bc]"
输出:"aaabcbc"

输入:s = "3[a2[c]]"
输出:"accaccacc"

输入:s = "2[abc]3[cd]ef"
输出:"abcabccdcdcdef"
java

🤔 思维发展历程#

1. 初学者思路#

可能会想到用简单的字符串替换。但遇到嵌套结构时(如”3[a2[c]]”),这种方法就难以处理了。

2. 栈的思路#

利用栈来处理嵌套结构,遇到’]‘时弹出栈内元素直到遇到’[‘,处理这一层的重复。

3. 递归思路#

将问题分解为子问题:每遇到一个’[‘就是一个新的子问题的开始,遇到对应的’]‘就是子问题的结束。

🚀 优雅的递归解决方案#

📝 代码详解#

让我们深入理解这个递归解决方案的精妙之处:

1. 全局索引设计#

使用全局索引来追踪当前处理的字符位置,这样可以在递归调用间共享处理进度。

2. 状态处理#

代码处理三种主要状态:

  • 遇到数字:收集完整数字,然后递归处理方括号内的内容
  • 遇到字母:直接添加到结果中
  • 遇到’]‘:表示当前层级处理完成,返回结果

3. 数字处理#

考虑到数字可能是多位数,使用循环来获取完整的数字值:

// 当前片段演示如何解析多位数字(例如 "123[a]" 中的 123)
int count = 0;
while (Character.isDigit(s.charAt(index))) {
    // 十进制累加:先左移一位(*10),再加当前数位
    count = count * 10 + (s.charAt(index) - '0');
    // 游标右移,读取下一位数字
    index++;
}
java

4. 递归精髓#

每次遇到’[‘就会触发一次递归调用,处理括号内的内容。递归函数返回时,正好处理完一对括号内的内容。

🎯 易错点剖析#

  1. 数字处理

    • 别忘了处理多位数字
    • 注意数字到字符的转换
  2. 嵌套处理

    • 正确处理嵌套的括号结构
    • 保持对递归层级的清晰理解
  3. 索引管理

    • 准确移动和更新索引位置
    • 处理边界情况

💡 举一反三#

这种解码思想可以应用到多种场景:

  1. HTML解析

    • 处理嵌套的HTML标签结构
    • 构建DOM树
  2. 表达式求值

    • 处理带括号的数学表达式
    • 计算器的实现
  3. 文件压缩

    • 实现简单的文本压缩算法
    • 处理重复模式

🎨 图解演示#

🌟 面试技巧#

  1. 思路说明

    • 先解释为什么选择递归方案
    • 说明递归终止条件和状态传递
  2. 复杂度分析

    • 时间复杂度:O(n),其中n是解码后的字符串长度
    • 空间复杂度:O(n),递归调用栈的深度
  3. 优化讨论

    • 可以讨论迭代方案的实现
    • 考虑内存优化的可能性

🎩 栈解法版本#

除了递归,我们还可以用栈来解决这个问题:

这个栈解法的优点是:

  1. 避免了递归调用的开销
  2. 更容易理解状态的变化过程
  3. 适合处理超大规模的输入

这道题展示了如何优雅地处理嵌套结构,无论是使用递归还是栈,都体现了解决复杂问题的不同思维方式。如果你对这个问题还有任何疑问,欢迎在评论区讨论!