0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

LeetCode 394:字符串解码

算法与数据结构 来源:吴师兄学算法 作者:吴师兄学算法 2022-08-31 15:57 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

今天的题目来源于 LeetCode 第 394 号问题:字符串编码,难度为「中等」,根据评论区的反馈,近期华为面试、字节面试都出现过。

0a45d7d4-28dd-11ed-ba43-dac502259ad0.png0a61357e-28dd-11ed-ba43-dac502259ad0.png

一、题目描述

给定一个经过编码的字符串,返回它解码后的字符串。

编码规则为:k[encoded_string],表示其中方括号内部的encoded_string正好重复k次。注意k保证为正整数。

你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。

此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数k,例如不会出现像3a2[4]的输入。

示例 1:

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

示例 2:

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

示例 3:

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

示例 4:

输入:s ="abc3[cd]xyz"
输出:"abccdcdcdxyz"

提示:

  • 1 <= s.length <= 30
  • s由小写英文字母、数字和方括号'[]'组成
  • s保证是一个有效的输入。
  • s中所有整数的取值范围为[1, 300]

二、题目解析

注意示例 2 ,可以发现字符串中存在括号内有嵌套括号的情况,这个时候,只有先把内层括号解码成功,才能再去解码外层括号。

0a7d0254-28dd-11ed-ba43-dac502259ad0.png

也就意味着后面访问的括号比前面访问的括号还更早的进行处理,与栈的先入后出特点对应。

所以,本题使用栈来处理。

具体操作如下:

1、构建两个栈,一个是数字栈numStack,在遍历编码字符串过程中记录出现的数字;一个是字符串栈strStack,在遍历编码字符串过程中记录出现的字符串。

2、初始化两个变量,一个是digit,用来记录访问到字符串之前出现的数字;一个是res,在访问编码字符串的过程中,把得到的结果存放到 res 中。

3、接下来,开始从头到尾访问编码字符串,在访问过程中,字符会出现 4 种情况。

0a9739d0-28dd-11ed-ba43-dac502259ad0.png

4、如果是数字,需要把字符转成整型数字,然后更新到digit上,代表后续的字符串需要重复digit次。

5、如果是字符,说明它就出现一次,可以直接存放到 res 中。

6、如果是"[" ,这个时候出现了嵌套的内层编码字符串,而外层的解码需要等待内层解码的结果,那么之前已经扫描的字符需要存放起来,等到内层解码之后再重新使用。

0ab9202c-28dd-11ed-ba43-dac502259ad0.png

7、如果是"]" ,此时,内层解码已经有结果,需要把它和前面的字符串进行拼接。

8、拼接的方式就是先通过 numsStack 的栈顶元素获取重复的次数,再通过 strStack 的栈顶元素获取前面的字符串。

9、最后返回 res 就行。

三、参考代码

1、Java 代码

//登录AlgoMooc官网获取更多算法图解
//https://www.algomooc.com
//作者:程序员吴师兄
//代码有看不懂的地方一定要私聊咨询吴师兄呀
//字符串解码(LeetCode394)//leetcode.cn/problems/decode-string/
classSolution{
publicStringdecodeString(Strings){

//创建数字栈,在遍历编码字符串过程中记录出现的数字
DequenumStack=newLinkedList<>();

//创建字符栈,在遍历编码字符串过程中记录出现的字符串
DequestrStack=newLinkedList<>();

//在访问编码字符串的过程中,用来记录访问到字符串之前出现的数字,一开始为0
intdigit=0;

//在访问编码字符串的过程中,把得到的结果存放到res中
StringBuilderres=newStringBuilder();

//从头到尾遍历编码字符串
for(inti=0;i< s.length(); i++) {

            //在遍历过程中,字符会出现4种情况

//先获取此时访问的字符
charch=s.charAt(i);

//1、如果是数字,需要把字符转成整型数字
//注意数字不一定是1位,有可能是多位
//比如123a,在字母a的前面出现了123,表示a重复出现123次
//那么一开始ch为1,当访问到ch为2的时候,1和2要组成数字12
//再出现3,12和3组成数字123
if(Character.isDigit(ch)){

//先将字符转成整型数字ch-‘0’
//补充知识:将字符'0'-'9'转换为数字,只需将字符变量减去'0'就行
//因为字符和数字在内存里都是以ASCII码形式存储的
//减去'0',其实就是减去字符'0'的ASCII码,而字符'0'的ASCII码是30
//所以减去'0'也就是减去30,然后就可以得到字符对应的数字了。
intnum=ch-'0';

//再将这个数字和前面存储的数字进行组合
//1和2组成数字12,也就是1*10+2=12
//12和3组成数字123,也就是12*10+3=123
digit=digit*10+num;

//2、如果是字符
}elseif((ch>='a'&&ch<= 'z')){

//说明它就出现一次,可以直接存放到res中
res.append(ch);

//3、如果是"["
//出现了嵌套的内层编码字符串,而外层的解码需要等待内层解码的结果
//那么之前已经扫描的字符需要存放起来,等到内层解码之后再重新使用
}elseif(ch=='['){

//把数字存放到数字栈
numStack.push(digit);

//把外层的解码字符串存放到字符串栈
strStack.push(res);

//开始新的一轮解码
//于是,digit归零
digit=0;

//res重新初始化
res=newStringBuilder();

//4、如果是"]"
}elseif(ch==']'){

//此时,内层解码已经有结果,需要把它和前面的字符串进行拼接

//第一步,先去查看内层解码的字符串需要被重复输出几次
//比如e3[abc],比如内层解码结果abc需要输出3次
//通过数字栈提取出次数
intcount=numStack.poll();

//第二步,通过字符串栈提取出之前的解码字符串
StringBuilderoutString=strStack.poll();

//第三步,不断的把内层解码的字符串拼接起来
for(intj=0;j< count; j++) {
                    
                    //拼接到outString后面,拼接count次
outString.append(res.toString());
}

//再把此时得到的结果赋值给res
res=outString;
}
}

//返回解码成功的字符串
returnres.toString();
}
}

2、C++ 代码

classSolution{
public:
stringdecodeString(strings){
//创建数字栈,在遍历编码字符串过程中记录出现的数字
stack<int>numStack;

//创建字符栈,在遍历编码字符串过程中记录出现的字符串
stack<string>strStack;

//在访问编码字符串的过程中,用来记录访问到字符串之前出现的数字,一开始为0
intdigit=0;

//在访问编码字符串的过程中,把得到的结果存放到res中
stringres;

//从头到尾遍历编码字符串
for(inti=0;i< s.size(); i++) {

            //在遍历过程中,字符会出现4种情况

//先获取此时访问的字符
charch=s[i];
//1、如果是数字,需要把字符转成整型数字
//注意数字不一定是1位,有可能是多位
//比如123a,在字母a的前面出现了123,表示a重复出现123次
//那么一开始ch为1,当访问到ch为2的时候,1和2要组成数字12
//再出现3,12和3组成数字123
if(ch>='0'&&ch<='9'){

//先将字符转成整型数字ch-‘0’
//补充知识:将字符'0'-'9'转换为数字,只需将字符变量减去'0'就行
//因为字符和数字在内存里都是以ASCII码形式存储的
//减去'0',其实就是减去字符'0'的ASCII码,而字符'0'的ASCII码是30
//所以减去'0'也就是减去30,然后就可以得到字符对应的数字了。
intnum=ch-'0';

//再将这个数字和前面存储的数字进行组合
//1和2组成数字12,也就是1*10+2=12
//12和3组成数字123,也就是12*10+3=123
digit=digit*10+num;

//2、如果是字符
}elseif((ch>='a'&&ch<= 'z')){

//说明它就出现一次,可以直接存放到res中
res+=ch;

//3、如果是"["
//出现了嵌套的内层编码字符串,而外层的解码需要等待内层解码的结果
//那么之前已经扫描的字符需要存放起来,等到内层解码之后再重新使用
}elseif(ch=='['){

//把数字存放到数字栈
numStack.push(digit);

//把外层的解码字符串存放到字符串栈
strStack.push(res);

//开始新的一轮解码
//于是,digit归零
digit=0;

//res重新初始化
res="";

//4、如果是"]"
}elseif(ch==']'){

//此时,内层解码已经有结果,需要把它和前面的字符串进行拼接

//第一步,先去查看内层解码的字符串需要被重复输出几次
//比如e3[abc],比如内层解码结果abc需要输出3次
//通过数字栈提取出次数
intcount=numStack.top();

numStack.pop();

//第二步,通过字符串栈提取出之前的解码字符串
stringoutString=strStack.top();

strStack.pop();

//第三步,不断的把内层解码的字符串拼接起来
for(intj=0;j< count; j++) {
                    
                    //拼接到outString后面,拼接count次
outString+=res;
}

//再把此时得到的结果赋值给res
res=outString;
}
}

//返回解码成功的字符串
returnres;
}
};

3、Python 代码

classSolution:
defdecodeString(self,s:str)->str:
#创建数字栈,在遍历编码字符串过程中记录出现的数字
numStack=[]

#创建字符栈,在遍历编码字符串过程中记录出现的字符串
strStack=[]

#在访问编码字符串的过程中,用来记录访问到字符串之前出现的数字,一开始为0
digit=0

#在访问编码字符串的过程中,把得到的结果存放到res中
res=""

#从头到尾遍历编码字符串
forchins:

#在遍历过程中,字符会出现4种情况
#先获取此时访问的字符
#1、如果是数字,需要把字符转成整型数字
#注意数字不一定是1位,有可能是多位
#比如123a,在字母a的前面出现了123,表示a重复出现123次
#那么一开始ch为1,当访问到ch为2的时候,1和2要组成数字12
#再出现3,12和3组成数字123
if'0'<= ch <= '9':

#先将字符转成整型数字ch-‘0’
#补充知识:将字符'0'-'9'转换为数字,只需将字符变量减去'0'就行
#因为字符和数字在内存里都是以ASCII码形式存储的
#减去'0',其实就是减去字符'0'的ASCII码,而字符'0'的ASCII码是30
#所以减去'0'也就是减去30,然后就可以得到字符对应的数字了。
num=int(ch)

#再将这个数字和前面存储的数字进行组合
#1和2组成数字12,也就是1*10+2=12
#12和3组成数字123,也就是12*10+3=123
digit=digit*10+num

#2、如果是字符
elifch>='a'andch<= 'z':

#说明它就出现一次,可以直接存放到res中
res+=ch

#3、如果是"["
#出现了嵌套的内层编码字符串,而外层的解码需要等待内层解码的结果
#那么之前已经扫描的字符需要存放起来,等到内层解码之后再重新使用
elifch=='[':

#把数字存放到数字栈
numStack.append(digit)

#把外层的解码字符串存放到字符串栈
strStack.append(res)

#开始新的一轮解码
#于是,digit归零
digit=0

#res重新初始化
res=""

#4、如果是"]"
elifch==']':

#此时,内层解码已经有结果,需要把它和前面的字符串进行拼接

#第一步,先去查看内层解码的字符串需要被重复输出几次
#比如e3[abc],比如内层解码结果abc需要输出3次
#通过数字栈提取出次数
count=numStack.pop()

#第二步,通过字符串栈提取出之前的解码字符串
outString=strStack.pop()

#第三步,不断的把内层解码的字符串拼接起来
forjinrange(0,count):
#拼接到outString后面,拼接count次
outString+=res


#再把此时得到的结果赋值给res
res=outString

#返回解码成功的字符串
returnres

四、复杂度分析

  • 时间复杂度 O(N),一次遍历s
  • 空间复杂度 O(N),辅助栈在极端情况下需要线性空间。

审核编辑 :李倩


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 解码
    +关注

    关注

    0

    文章

    187

    浏览量

    28443
  • 字符串
    +关注

    关注

    1

    文章

    594

    浏览量

    23041

原文标题:LeetCode 394:字符串解码

文章出处:【微信号:TheAlgorithm,微信公众号:算法与数据结构】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    如何使用 NuMaker 板和 Mbed OS 上的连接字符串连接到 Azure IoT?

    使用 NuMaker 板和 Mbed OS 上的连接字符串连接到 Azure IoT
    发表于 09-04 07:46

    LM3466 多 LED 电流平衡器技术手册

    到电源的数或每个 LED 的正向电压 字符串。 如果任何 LED 灯在运行过程中打开,LM3466 会自动平衡通过所有剩余活动 LED 灯的电源电流。 如 因此,即使一些 LED
    的头像 发表于 08-29 14:27 852次阅读
    LM3466 多<b class='flag-5'>串</b> LED 电流平衡器技术手册

    labview如何生成一个带字符串返回的dll

    labview如何生成一个dll,如下图,要求一个输入,类型是字符串,返回类型也是字符串
    发表于 08-28 23:20

    在Python中字符串逆序有几种方式,代码是什么

    对于一个给定的字符串,逆序输出,这个任务对于python来说是一种很简单的操作,毕竟强大的列表和字符串处理的一些列函数足以应付这些问题 了,今天总结了一下python中对于字符串的逆序输出的几种常用
    的头像 发表于 08-28 14:44 784次阅读

    SQL 通用数据类型

    如何与存储的数据进行交互。 下面的表格列出了 SQL 中通用的数据类型: 数据类型 描述 CHARACTER(n) 字符/字符串。固定长度 n。 VARCHAR(n) 或 CHARACTER VARYING(n) 字符/
    的头像 发表于 08-18 09:46 576次阅读

    harmony-utils之StrUtil,字符串工具类

    harmony-utils之StrUtil,字符串工具类 harmony-utils 简介与说明 [harmony-utils] 一款功能丰富且极易上手的HarmonyOS工具库,借助众多实用工具类
    的头像 发表于 07-03 11:32 369次阅读

    基于RK3576的BASE64编解码

    参数、返回值及注意事项。最后,通过两个示例代码展示了如何对字符串进行BASE64编码和解码,并验证了数据中包含0x00时的处理方式。
    的头像 发表于 05-12 13:41 439次阅读
    基于RK3576的BASE64编<b class='flag-5'>解码</b>

    如何锁定和解锁S32K394/96系列的JTAG?

    如何锁定和解锁 S32K394/96 系列的 JTAG 端口 我们需要配置 DCF 和 UTEST 闪存吗? 如果是,请分享配置和 UTEST 内存详细信息以锁定和解锁。 如果没有,请分享如何锁定和解锁 JTAG 端口的信息? 也请分享程序文件
    发表于 03-26 06:23

    STM32C031C6使用的是UART2通讯,通过printf()函数发送字符串时,汉字错码怎么解决?

    使用的是UART2通讯,通过printf()函数发送字符串时,汉字错码(见下图),应该是KEIL哪里没有设置好的问题。 启用了UART2的中断接收,可以接收到串口调试助手的数据,但是缓存区的指针没有归零,下次接收时缓存区中的内容接续(如下图所示),不知道用什么命令来清除缓存区(即让指针归零)。
    发表于 03-07 12:30

    请问如何用Verilog实现将ascaii码数值字符串转换成定点数?

    我需要接收一个ascaii码字符串,内容是12位有效数字的数值,带小数。我不知道怎么把小数部分转换成定点数。
    发表于 01-23 21:57

    字符串在数据库中的存储方式

    数据库是现代信息技术中存储和管理数据的核心组件。字符串作为最常见的数据类型之一,在数据库中的存储方式对其性能和可扩展性有着重要影响。 数据类型 固定长度字符串 :如CHAR类型,它为每个字符串分配
    的头像 发表于 01-07 15:41 1251次阅读

    字符串在编程中的应用实例

    字符串在编程中有着广泛的应用,它们被用于表示文本数据、处理用户输入、构建动态内容等。以下是一些字符串在编程中的应用实例: 1. 用户输入与输出 用户输入 :程序通常需要从用户那里获取输入,这些输入通
    的头像 发表于 01-07 15:33 1131次阅读

    字符串字符数组的区别

    在编程语言中,字符串字符数组是两种基本的数据结构,它们都用于存储和处理文本数据。尽管它们在功能上有一定的重叠,但在内部表示、操作方式和使用场景上存在显著差异。 1. 内部表示 字符串 字符串
    的头像 发表于 01-07 15:29 1677次阅读

    字符串反转的实现方式

    在编程中,字符串反转是一个基础而重要的操作,它涉及到将一个字符串中的字符顺序颠倒过来。这个操作在多种编程语言中都有不同的实现方式,本文将探讨几种常见的字符串反转方法。 1. 递归方法
    的头像 发表于 01-07 15:27 1243次阅读

    字符串处理方法 字符串转数字的实现

    在编程中,将字符串转换为数字是一个常见的需求。不同的编程语言有不同的方法来实现这一功能。以下是一些常见编程语言中的字符串转数字的实现方法: Python 在Python中,可以使用内置的 int
    的头像 发表于 01-07 15:26 1399次阅读