算法设计与应用基础 - Week01
博客动机
其实一直挺想开个技术博客,一方面可以整理自己的知识库,一方面也可以通过交流、填坑来激励自己的成长。不过就像林老师说的那样,觉得发表到博客上的东西必须经得起考验,而自己恰恰没有那么扎实的基础,所以迟迟没有行动。
这次因为课程的原因,不得不把自己浅薄的见解发表于此,希望能够以此为契机,养成写博客的习惯:);也希望自己能够成为一个负责任的博主,博文里大概会有许多错误,希望各位朋友、同学能够指出,我会坚持修补的 √
第一周目标
自数据结构课程结束以来几乎就没有用过C++了,要么是操作系统实验里连库都要自己写的C语言,要么是实验室里的Python,总的来说,C++已经完全荒废了…orz
所以前几周主要是让自己重新熟悉C++,不去挑选特定类别的题目,而是使用LeetCode的Pick One功能来随机选择。
LeetCode 385. Mini Parser
抽到的第一题题意很直观,也就是解析字符串并用题目给定的类表示出来;字符串有两种类型,一种表示单整数,另一种表示嵌套列表类型。
观察给定类的接口
因为题目要求最终结果用给定的类表示,首先要理清给定类的接口。简单梳理一下类的接口,可以表示成下面的结构图(这种表示方法或许不太规范,如果同学们有简明规范的表示方法,希望能给我安利一下~)。
class NestedInteger
|--- Constructor
| |--- NestedInteger()
| |--- NestedInteger(int value)
|
|--- Single Integer
| |--- isInteger(): bool const
| |--- getInteger(): int const
| |--- setInteger(int value): void
|
|--- Nested Integer
| |--- add(const NestedInteger &ni): void
| |--- getList(): const vector<NestedInteger> & const
因为这题只涉及列表的构造,基本上只需要用到两个构造函数以及成员函数add,其他暂时就不需要理会了。
解析单整数
单整数的解析非常简单,题目给出
String contains only digits
0-9
,[
,-
,,
,]
.
因此负数也包括在内,解析单整数的时候需要先判断符号,然后依次解析数字。用一个成员函数表示如下:
int parseNum(string s) {
if (s.empty()) return 0;
bool is_neg = false;
int i, num = 0;
if (s[0] == '-') is_neg = true, i = 1;
else i = 0;
for (; i < s.size(); i++) {
num *= 10;
num += (s[i] - '0');
}
return is_neg == true ? -num : num;
}
使用递归解析嵌套列表
解决嵌套问题一个最直观的方法便是递归,递归基可以是单个整数,也可以是空。前面已经写出了单整数的解析函数,这部分只要把递归步表示出来就可以了。
问题在于如何表示递归步。可以观察到,一个嵌套列表总是由成对 []
包围,处理一个嵌套列表的字符串时,只需要考虑字符串下标为 [1, size - 1) 的部分就可以了。
如果元素是单整数,那么子串的首位一定不是 [
,遇到字符 ,
或字符串遍历完成则表示到达子串的尾部,得到子串在字符串中的首位和尾部即可以将其作为递归步的输入。
beg = i;
/* other codes */
// A single integer
else if (s[i] != '[') {
i++;
for (; i < s.size() - 1; i++) {
if (s[i] == ',') break;
}
out.add( deserialize( s.substr(beg, i - beg) ) );
}
如果元素是嵌套列表,那么要统计 [
和 ]
出现的次数。使用变量 cnt
进行计数,遇到字符 [
时变量 cnt
加1,遇到字符 ]
时变量 cnt
减1,一旦变量 cnt
的值为0,则表示获得了一个嵌套列表子串。
// A nested list
else {
cnt = 1; i++;
for (; i < s.size() - 1; i++) {
if (s[i] == '[') cnt++;
else if (s[i] == ']') {
cnt--;
if (cnt == 0) {
i++;
break;
}
}
}
out.add( deserialize( s.substr(beg, i - beg)) );
}
完整代码如下:
class Solution {
public:
NestedInteger deserialize(string s) {
if (s.empty()) return NestedInteger();
if (s[0] != '[') return NestedInteger( parseNum(s) );
NestedInteger out;
int beg, cnt;
for (int i = 1; i < s.size() - 1; i++) {
beg = i;
if (s[i] == ',');
else if (s[i] == ']');
// A single integer
else if (s[i] != '[') {
i++;
for (; i < s.size() - 1; i++) {
if (s[i] == ',') break;
}
out.add( deserialize(s.substr(beg, i - beg)) );
}
// A nested list
else {
cnt = 1; i++;
for (; i < s.size() - 1; i++) {
if (s[i] == '[') cnt++;
else if (s[i] == ']') {
cnt--;
if (cnt == 0) {
i++;
break;
}
}
}
out.add( deserialize( s.substr(beg, i - beg)) );
}
}
return out;
}
int parseNum(string s) {
if (s.empty()) return 0;
bool is_neg = false;
int i, num = 0;
if (s[0] == '-') is_neg = true, i = 1;
else i = 0;
for (; i < s.size(); i++) {
num *= 10;
num += (s[i] - '0');
}
return is_neg == true ? -num : num;
}
};
第一次写太过啰嗦了…有空的时候精简一下…orz