decodeString

此题是leetCode 394

第一个版本写的非常挫折,代码也十分混乱。比较大的收获是gdb调试熟悉多了. 这也是比较挫的实现,让人失之东隅收之桑榆吧! 总结一些心得:

  • 先不要着急开始写;
  • 有些情况是递归方便, 有些情况是非递归方便(例如按层遍历树, 包括此题). 前提是, 如果需要递归把递归的操作拆解清楚(返回类型, 入参等); 对于递归情况很复杂的,尝试拆解手工栈的操作;
  • 对于这种明显利用栈的, 先把栈操作的内容搞清楚, 入栈出栈都是哪些内容? 时机是哪些? 出栈后的具体动作是什么? 此题解法2,3中是数字和字符入栈,而不是’[’, '['只是标记入栈的时机。这些问题没有搞清,就不要想着直接去走递归利用系统栈去得到解法。如果顺利可以得到,但大概率会不顺利。对于设计其他数据结构的把基本操作也先尝试搞清.
  • 有关解析状态:
    • 一般还是写一下BNF表达式比较好(而不是直接用脑子想),有助于搞清楚所处的若干个状态; 理解下一个字符对状态转换的分支的作用; 有关这点参考一下第一个递归解法的注释;
    • 先搞1个或几个具体的例子,拆解解析字符的每一步的动作应该是什么(入栈, 出栈, 具体动作, etc.)
  • 使用iterator或integer counter不是问题关键。搞清前面2项才是关键;

解法1: 最初的递归版本

#include <iostream>
#include <cctype>
#include <string>
#include <vector>using namespace std;class Solution {public:string decodeString(const string &s);private:vector<char> stack_;int parse_repeat_num_(string::const_iterator *beg); string decodeString_(string::const_iterator *beg);string makeup_partial_string(int repeat_num, const string& str);string handleStartWithDigit(string::const_iterator *beg);
};int Solution::parse_repeat_num_(string::const_iterator *beg) {string repeat_num_str = "";while (isdigit(**beg)) {repeat_num_str += **beg;(*beg)++;}      return stoi(repeat_num_str);
}string Solution::decodeString(const string& s) {auto st = s.cbegin(), ed = s.cend();string ans("");do {string tmp = decodeString_(&st);ans += tmp;cout << "tmp=" << tmp << endl;} while (st != ed);cout << "result=" << ans << endl; return ans;
}string Solution::makeup_partial_string(int repeat_num, const string& str) {string tmp = str;string result = string(str); while (--repeat_num) {result += tmp;}    return result;
}string Solution::handleStartWithDigit(string::const_iterator *beg) {auto *st = beg;string ans;if (isdigit(**st)) {int repeat_num = parse_repeat_num_(st);if (**st == '[') {stack_.push_back('[');(*st)++;ans = decodeString_(st);if (**st == ']') {stack_.pop_back();(*st)++; // point to the next one after ']';ans = makeup_partial_string(repeat_num, ans); return ans;}throw runtime_error("Error: handleDigit error");} else {throw runtime_error("Error: handleDigit error");} }return "";
}// BNF:
// <decode_string> ::= <decode_string>{, <decode_string>}  //1
// decode_string ::= [<digits> ] "[" <decode_string> "]"  //2
//
// 这个解法的decodeString_承担着2个职能,从handleStartWithDigit的调用,
// 需要将结果返回给handleStartWithDigit;通过stack_计数的,则由stack的状态控制(因为同一层的decode_string可能有多个并列的递归定义);
// 这导致返回的出口有好几处,结合不同状态,这让代码很不清晰;
//
string Solution::decodeString_(string::const_iterator *beg) {auto *st = beg;string ans = "";do {if (isdigit(**st)) {ans += handleStartWithDigit(st);if (**st == ']') {// 一个handleStartWithDigit结构解析出(已经处理了digit对应的], 下一个仍是]), 返回上一层;return ans;}} else if (isalpha(**st)) {string tmp;alpha_label: while (isalpha(**st)) {char c = **st;tmp += string(1, c);(*st)++;}ans += tmp;tmp = "";if (isdigit(**st)) {tmp = handleStartWithDigit(st);ans += tmp;tmp = "";goto alpha_label;}if (**st == ']') {// 字符结构的结束标志是], 返回调用decode_string_的上一层return ans;}}} while(stack_.size() != 0);return ans;
};int main() {Solution solution;string s = "3[a]2[bc]";  string s1 = "3[a2[c]]"; string s2 = "2[2[bc]]";solution.decodeString(s2);  // bcbcbcbcsolution.decodeString(s1);  // accaccaccsolution.decodeString(s);   // aaabcbcreturn 0;
}

解法2,3: 非递归实现

阅读了leetCode上的题解, 又写了以下2个非递归解法。入栈内容是数字和字符; 代码清晰了许多。 时间复杂度O(n)
空间复杂度最大也小于O(n);

解法2:

#include <iostream>
#include <stack>using namespace std;class Solution {public:string decodeString(const string &s) {int n = s.size();int num = 0;string current_str("");for (int i = 0; i < n; ++i) {char c = s[i];if (isdigit(c)) {num = num * 10 + (c - '0');} else if (c == '[') {num_stack_.push(num);num = 0;str_stack_.push(current_str);current_str = "";} else if (isalpha(c)) {current_str += string(1, c);} else if (c == ']') {string str_top = str_stack_.top();int num_top = num_stack_.top();str_stack_.pop();num_stack_.pop();string tmp = current_str;while (--num_top) {current_str += tmp;}current_str = str_top + current_str;}}cout << "result: current_str=" << current_str << endl;return current_str;}private:stack<int> num_stack_;stack<string> str_stack_;
};int main() {Solution solution;string s = "3[a]2[bc]";string s1 = "3[a2[c]]"; string s2 = "2[2[bc]]";solution.decodeString(s2);solution.decodeString(s1);solution.decodeString(s);return 0;
}

解法3:

#include <iostream>
#include <stack>
#include <string>using namespace std;class Solution {public:string decodeString(const string &s) {auto st = s.cbegin(), ed = s.cend();int num = 0;string current_str("");// 使用iterator与否并不重要;for (; st != ed; ++st) {char c = *st;if (isdigit(c)) {num = parse_repeat_num(&st);} else if (c == '[') {num_stack_.push(num);num = 0;str_stack_.push(current_str);current_str = "";} else if (isalpha(c)) {current_str += string(1, c);} else if (c == ']') {string str_top = str_stack_.top();int num_top = num_stack_.top();str_stack_.pop();num_stack_.pop();string tmp = current_str;while (--num_top) {current_str += tmp;}current_str = str_top + current_str;}}cout << "result: current_str=" << current_str << endl;return current_str;}private:stack<int> num_stack_;stack<string> str_stack_;int parse_repeat_num(string::const_iterator *beg) {auto st = *beg;string res("");while (isdigit(*st)) {res += *st;st++;}*beg = st - 1;return stoi(res);}
};int main() {Solution solution;string s = "3[a]2[bc]";string s1 = "3[a2[c]]"; string s2 = "2[2[bc]]";solution.decodeString(s2);solution.decodeString(s1);solution.decodeString(s);return 0;
}

gdb 调试tip

// 需要用-g, 生成符号表; 否则gdb会报No symbol table is loaded, error;
// g++会自动调用ld,使用linker生成binary可执行文件, gcc不会; 会报出undefined reference error
g++ -g -std=c++11 -Wall 394.cpp -o main_394
gdb -q main_394

其他: s, n, p, file. etc.

结果

总结

重申一下总结要点:

  • 此题的递归解法很难搞定, 所以注意某些情况是递归较容易,某些情况例如涉及状态机的情形,递归并不一定容易写出。此题在写解法1时,画了好复杂的一张状态转换图,并恰好直觉的将处理数字开头和‘[’开头的部分区分为2部分, 又发现必须利用栈来控制同一层字符中混有多个数字的情况,较顺利的得到结果。但尝试合并handleStartWithDigit和decodeString_2者并不成功,递归十分难写。
  • 结合具体例子,搞清怎么设计栈内容,入栈时机和出栈时机,是较快较容易解出本题的关键;

decodeString相关推荐

  1. LeetCode 394: DecodeString (Java)

    解码题. 编码规则直接看例子(编码后字符串->原字符串): 2[b] -> bb 3[a2[c]] -> 3[acc] -> accaccacc 2[a2[b]ef]xy -& ...

  2. Go 学习笔记(41)— Go 标准库之 encoding/base64 (编解码)

    1. 简要概述 Base64 是网络上最常见的用于传输 8Bit 字节码的编码方式之一, Base64 就是一种基于 64 个可打印字符来表示二进制数据的方法. Base64 编码是从二进制到字符的过 ...

  3. 力扣(LeetCode)刷题,简单+中等题(第26期)

    目录 第1题:字典序排数 第2题:字符串解码 第3题:查找常用字符 第4题:所有奇数长度子数组的和 第5题:长按键入 第6题:分割字符串的最大得分 第7题:回文链表 第8题:有多少小于当前数字的数字 ...

  4. linux镜像修改密码,OpenStack 镜像修改密码方案

    现在各大linux厂商,其实已经有专门给openStack提供的镜像,不过国内的朋友,不太习惯老外做镜像的方式,经常问密码是多少.本博客提供几种修改密码方案,仅供参考. 前言 对OpenStack云主 ...

  5. 3des java 库_java 3DES 加密

    public class DESCode { private String algorithm = "DESede/CBC/PKCS7Padding";//加密方法/运算模式/填充 ...

  6. python之模块base64

    # -*- coding: cp936 -*- #python 27 #xiaodeng>>> help(base64) #用来作base64编码解码 FUNCTIONS #函数(功 ...

  7. IOS、java支持DES加密

    最近在考虑数据加密方面的需求,所以对数据加密简单的看了一下,当然不是看的原理,只是看看怎么能够实现.现在我们需要实现的是移动端和后台(java)数据加解密的配合,开始的时候考虑的使用RSA,因为RSA ...

  8. 刷前端面经笔记(十一)

    1.栈的压入和弹出 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序.假设压入栈的所有数字均不相等.例如序列1,2,3,4,5是某栈的压入顺序,序列5,4,3,2 ...

  9. 6.字符串解析(LeetCode第394题)

    分享一个容易理解的解法,个人觉得官方的不太好理解 代码实现 class Solution {public String decodeString(String s) {Stack<Integer ...

最新文章

  1. Git安装与Github基本使用(完整版 for mac)
  2. Android下对Cookie的读写操作(附Demo)
  3. 框架:spring总结
  4. SSAS : 使用.NET为SSAS编写自定义程序集(四)
  5. 【Python】自定义排序函数 - 示例
  6. 在 ASP.NET Core 中执行租户服务
  7. 如此如此,怎能师夷长技以制夷!
  8. case class和trait
  9. 洛谷P1073 最优贸易
  10. 计算机清理的作用,电脑也有自带的垃圾清理功能,甚至比众多清理软件更好用!...
  11. java jhap_Java-Live与JVAP工具的Max
  12. 2.权限管理准备工作:你应该知道的ASP.NET网站最基本的安全措施!
  13. cannot be cast to android.support.v4.app.Fragment
  14. PHP直播聊天室源码/财经直播源码/房间多开/游客互动/聊天审核
  15. Paper-----文献引用格式
  16. cadence SPB17.4 - 从正常PCB文件反推原理图
  17. [B2R]Raven: 2靶机
  18. 【英语:发音基础】A6.基础词汇-核心形容词
  19. 蓝牙、WiFi、ZigBee三大无线通信技术协议模块哪一个是最好的?
  20. 【问题解决】Error:(3, 46) java: 程序包org.springframework.context.annotation不存在

热门文章

  1. 航班编程代码c语言,航班查询系统C语言源程序
  2. Docker基本管理:上篇(Docker理论概述和基础命令)
  3. 哈佛《幸福课》 第1课 什么是积极心理学
  4. Nature:交互式语言的语音规划网络
  5. ORA-04098: trigger ‘xxx.xxx‘ is invalid and failed re-validation
  6. CATT在SAP系统中的应用
  7. 细胞穿透肽八精氨酸、 H2N-RRRRRRRR-OH、 148796-86-5
  8. Google Adwords关键词广告须注意的7个问题
  9. 知乎周源微信_每周源代码30-具有XML文字的VB.NET作为ASP.NET MVC的视图引擎
  10. 培训班出身的前端,出路在哪儿?