【经典面试】87 字符串解码

news2024/9/26 3:30:28

字符串解码

    • 题解1 递归(程序栈)——形式语言自动机(LL(1)) : O(S)
      • 另一种递归(直观)
    • 题解2 2个栈(逆波兰式)
      • 1个栈(参考官方,但是不喜欢)

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

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

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

此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数 k ,例如不会出现像 3a 或 2[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]

题解1 递归(程序栈)——形式语言自动机(LL(1)) : O(S)

class Solution {
    int idx;
public:
    int getdigits(string& s){
        int ret = 0;
        while(idx < s.size() && isdigit(s[idx])){
            ret = ret*10 + s[idx++]-'0';
        }
        return ret;
    } 
    string getstring(string& s){
        // 结束条件
        if(idx == s.size() || s[idx] == ']')
            return string("");
        // 当前字符
        char cur = s[idx];
        // 重复次数置1
        int rep = 1;
        // 返回值
        string ret = "";

        // condition:如果是数字
        if(isdigit(cur)){
            int rep = getdigits(s);
            string str = "";
            // 跳左括号
            idx ++;

            // 顺序很重要:跳完左括号就要 取后面的string
            str = getstring(s);

            // 跳右括号
            idx ++;
            // 后--
            while(rep--){
                ret += str;
            }
        }
        // condition:如果是字母
        else if(isalpha(cur)){
            ret = string(1, s[idx++]);
        }
        return ret+getstring(s);
    }
    string decodeString(string s) {
        idx = 0;
        return getstring(s);
    }
};

在这里插入图片描述

另一种递归(直观)

class Solution {

public:
    string decodeString(string s) {
        string res = "";
        for(int i = 0; i < s.size(); i++){
        	// 字符
            if(s[i]>='a' && s[i] <= 'z'){
                res += s[i];
            // 左括号或者数字
            }else{
                int rep = 0;
                while(s[i] >= '0' && s[i] <= '9'){
                    rep = rep*10 + s[i++]-'0';
                }
                int curp = i+1;
                int lnum = 1;
                while(lnum){
                    i ++; // i最后是下一次解决的一段字符串的结尾([[[..]]],左括号要和右括号数对上)
                    if(s[i] == '[') lnum++;
                    if(s[i] == ']') lnum--;
                }
                string str = decodeString(s.substr(curp, i-curp));
                while(rep --){
                    res += str;
                }
            }
        }
        return res;
    }
};

在这里插入图片描述

题解2 2个栈(逆波兰式)

class Solution {

public:
    string decodeString(string s) {
        stack<int> num_stk; // 数字栈
        stack<string> str_stk; // 字符串栈
        string res = ""; // 当前累积的字符串
        // 逆波兰式
        for(int i = 0; i < s.size(); i++){
            if(isdigit(s[i])){
                int tmp = s[i]-'0';
                while(isdigit(s[++i]))
                    tmp = tmp*10 + s[i]-'0';
                num_stk.push(tmp);
                i --; // for 有自增
            }
            else if(s[i] == '['){
                str_stk.push(res); // 把上一段存起来
                res = ""; // 清空,开始累积该左括号后面的字符串
            }else if(s[i] == ']'){
                string tmp = "";
                int rep = num_stk.top();
                num_stk.pop();

                while(rep--)
                    tmp += res;
                
                res = str_stk.top() + tmp;
                str_stk.pop();
            }else{
                res += s[i]; 
            }
        }
        return res;
    }
};

在这里插入图片描述

1个栈(参考官方,但是不喜欢)

class Solution {
public:
    string getDigits(string &s, size_t &ptr) {
        string ret = "";
        while (isdigit(s[ptr])) {
            ret.push_back(s[ptr++]);
        }
        return ret;
    }

    string getString(vector <string> &v) {
        string ret;
        for (const auto &s: v) {
            ret += s;
        }
        return ret;
    }

    string decodeString(string s) {
        vector <string> stk;
        size_t ptr = 0;

        while (ptr < s.size()) {
            char cur = s[ptr];
            if (isdigit(cur)) {
                // 获取一个数字并进栈
                string digits = getDigits(s, ptr);
                stk.push_back(digits);
            } else if (isalpha(cur) || cur == '[') {
                // 获取一个字母并进栈
                stk.push_back(string(1, s[ptr++])); 
            } else {
                ++ptr;
                vector <string> sub;
                while (stk.back() != "[") {
                    sub.push_back(stk.back());
                    stk.pop_back();
                }
                // sub push的顺序是逆序,累积前需要反过来
                reverse(sub.begin(), sub.end());
                // 左括号出栈
                stk.pop_back();
                // 此时栈顶为当前 sub 对应的字符串应该出现的次数
                int repTime = stoi(stk.back()); 
                stk.pop_back();
                string t, o = getString(sub);
                // 构造字符串
                while (repTime--) t += o; 
                // 将构造好的字符串入栈
                stk.push_back(t);
            }
        }

        return getString(stk);
    }
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1151591.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux 权限管理(二)

文件类型和访问权限&#xff08;事物属性&#xff09; linux前都会有一串这个字符&#xff0c;第二字符到第九字符分别表示拥有者&#xff0c;所属组&#xff0c;和other所对应的权限。那么第一个字符表示什么呢&#xff1f; 第一个字符表示文件类型&#xff1a; d&#xff1a…

开放式耳机百元价位推荐哪款比较好一点、最值得入手的开放式耳机

不知道有没有和我一样的朋友&#xff0c;在工作的时候喜欢带着耳机&#xff0c;享受音乐带来的愉悦。然而&#xff0c;传统的入耳式耳机在长时间佩戴时会给耳朵带来不适感&#xff0c;甚至损害听力。 因此我现在会使用开放式耳机&#xff0c;采用了开放式设计&#xff0c;不需…

流程封装与基于加密接口的测试用例设计

接口测试仅仅掌握 Requests 或者其他一些功能强大的库的用法&#xff0c;是远远不够的&#xff0c;还需要具备能根据公司的业务流程以及需求去定制化一个接口自动化测试框架的能力。所以&#xff0c;接下来&#xff0c;我们主要介绍下接口测试用例分析以及通用的流程封装是如何…

算法通关村第四关-青铜挑战基于链表完成栈

大家好我是苏麟 , 今天聊聊. 本期大纲 栈的基础知识栈的特征栈的操作Java中的栈 基于链表实现栈 栈的基础知识 栈的特征 栈和队列是比较特殊的线性表&#xff0c;又称之为访问受限的线性表。栈是很多表达式、符号等运算的基础&#xff0c;也是递归的底层实现。理论上递归能做…

进阶课5——人工智能数据分类

数据类型是指数据在计算机中的存储方式&#xff0c;根据数据的不同特征和表示方式&#xff0c;可以将数据分为不同的类型。在IT领域中&#xff0c;随着数字化信息技术的应用不断扩大&#xff0c;数据的种类和格式也越来越多。 从人机交互数据类型的视角来看&#xff0c;人工智…

RSA加密解密

生成公钥私钥&#xff1a; /*** RSA 生成公钥私钥*/ public class CreateSecrteKey {public static final String KEY_ALGORITHM "RSA";private static final String PUBLIC_KEY "RSAPublicKey";private static final String PRIVATE_KEY "RSAPri…

pytorch复现1_VGG

不涉及太多原理 VGG在2014年由牛津大学著名研究组VGG (Visual Geometry Group) 提出&#xff0c;斩获该年ImageNet竞赛中 Localization Task (定位任务) 第一名 和 Classification Task (分类任务) 第二名。 网络亮点&#xff1a; 1.通过堆叠多个3x3的卷积核来替代大尺度卷积核…

腾讯云轻量应用服务器“镜像”怎么选择合适?

腾讯云轻量应用服务器镜像怎么选择&#xff1f;如果是用来搭建网站可以选择宝塔Linux面板腾讯云专享版&#xff0c;镜像系统根据实际使用来选择&#xff0c;腾讯云百科txybk.com来详细说下腾讯云轻量应用服务器镜像的选择方法&#xff1a; 腾讯云轻量应用服务器镜像选择 轻量…

常熟,一座服装之城的三重升级

“姐妹你别看我瘦&#xff0c;我的肚子是这样&#xff0c;我115斤……你看我这个靴子&#xff0c;一穿就是会秒变大长腿的那种。” 晚上九点。大楼十层的走廊里&#xff0c;隐隐传来一个女性的声音。 如果你是她的157万粉丝之一&#xff0c;此时此刻打开抖音&#xff0c;就能…

8.3 矢量图层点要素单一符号使用四

文章目录 前言单一符号&#xff08;Single symbol&#xff09;渲染填充标记&#xff08;Filled marker&#xff09;QGis代码实现 总结 前言 上一篇教程介绍了矢量图层点要素单一符号中椭圆形标记&#xff08;Ellipse marker&#xff09;和字符标记&#xff08;Font marker&…

【全志R128外设模块配置】USB外设功能配置

USB 外设功能配置 USB 功能简介 USB 功能模块包括了USB Host&#xff0c;USB Device 和OTG 功能。 USB Host 目前已经支持上的功能有&#xff1a;Mass Storage&#xff0c;UVC。 USB Device 目前已经支持上的功能有&#xff1a;ADB&#xff0c;UAC。 OTG 主要用作Host 与D…

极速指南:在 SpringBoot 中快速集成腾讯云短信功能

前言 今天分享一个SpringBoot集成腾讯云短信的功能&#xff0c;平常除了工作&#xff0c;很多xdm做自己的小项目都可能用到短信&#xff0c;但自己去看文档挺费劲的&#xff0c;我这边就帮你节省时间&#xff0c;直接把步骤给你列出来&#xff0c;照做就行。 实战 1、申请密…

python_PyQt5日周月K线纵向对齐显示_2_显示工具

目录 写在前面&#xff1a; 结果显示&#xff1a; 代码&#xff1a; 计算日数据、周数据&#xff0c;月数据&#xff0c;并返回 生成提示信息数据&#xff0c;同时将日周月合并到一个DataFrame中 返回K线图和成交量柱状图的数据 主界面&#xff0c;显示日周月对齐的K线图…

【思考】为什么要有随机分析,为什么要有频域变换

问&#xff1a;为什么要有随机分析&#xff0c;为什么要有频域变换&#xff1f; 答&#xff1a;因为原有的时域方法很难描述一些信号或噪声。 例如这样一个信号 如果要写出时域公式&#xff0c;简直是太复杂了&#xff0c;怎么描述它呢。一是从0时刻开始指数衰减。二是可以说…

基于SpringBoot的科研工作量管理系统

目录 前言 一、技术栈 二、系统功能介绍 管理员功能介绍 科研项目列表 项目论文信息管理 项目类型管理 三、核心代码 1、登录模块 2、文件上传模块 3、代码封装 四、系统测试 概要 系统测试的特点  系统功能测试 登录功能测试 添加项目类型功能测试 测试结果分…

微信一次性群发1000条消息:高效沟通的秘诀

在当今数字化时代&#xff0c;微信作为一款广受欢迎的社交应用程序&#xff0c;为人们提供了便捷的沟通方式。在微信中&#xff0c;一次性群发1000条消息似乎是一个不可能完成的任务&#xff0c;因为微信自带的群发功能是只能一次性最多群发200人的&#xff0c;那么有没有什么工…

uni-app打包之如何生成自由证书

我是使用Android Studio来直接生成。超级简单 第一步 打开 Android Studio 找到下面图片 第二步 选 Android App Bund 然后Next 第三步 选择创建新的 第四步 填写对应的 信息 密码最好都是一样的 第五步 点击ok 即可创建成功。 uniapp打包时候勾选文件 &#xff08;如果公…

C语言 指针进阶笔记

p和*p: 如图&#xff0c;p是指针&#xff0c;指针存放着地址&#xff0c;打印出来应该是数组的值 *p是指针里里面的元素 #include<stdio.h> int main() {int a1;int b2;int c3;int p[3]{a,b,c};printf("%d",*p); return 0; } 那么现在的打印结果应该为数组的…

线程是如何创建的

线程不是一个完全由内核实现的机制&#xff0c;它是由内核态和用户态合作完成的。pthread_create 不是一个系统调用&#xff0c;是 Glibc 库的一个函数&#xff0c;所以我们还要去 Glibc 里面去找线索。 首先处理的是线程的属性参数。例如前面写程序的时候&#xff0c;我们设置…