一、基本计算器Ⅲ
思路:
1. 确定递归函数:
- 计算括号内的数学表达式,并返回计算结果
2.大体流程(递归):
遍历字符串,直到遇到尾或‘)’:
- 遇到数字:将其压入到容器中
- 遇到操作符:在将其压入到容器前,若操作池的顶部是乘除,则计算数字池顶部并再次压入到数字池中
- 遇到'(' :进入递归并将结果压入到数字池中,并利用全局变量where记录递归后要遍历的位置
遍历完成后,注意末尾数字的遗漏计算问题(根据流程需要遇到字符才能将其压入)。
计算结果
更新where
代码:
class Solution {
public:
int where;
void push(vector<int>& num_vec, vector<char>& opt_vec, int cur) {
if (!opt_vec.size()) {
num_vec.push_back(cur);
return;
}
if (opt_vec.back() == '*') {
cur *= num_vec.back();
num_vec.pop_back();
num_vec.push_back(cur);
} else if (opt_vec.back() == '/') {
cur /= num_vec.back();
num_vec.pop_back();
num_vec.push_back(cur);
}
else num_vec.push_back(cur);
}
int cal(vector<int>& num_vec, vector<char>& opt_vec){
if(num_vec.size()==0)return 0;
int n=num_vec.size();
int ret=num_vec[0];
for(int i=1;i<n;++i){
if(opt_vec[i-1]=='+'){
ret+=num_vec[i];
}else ret-=num_vec[i];
}
return ret;
}
int f(string s, int i) {
vector<int> num_vec;
vector<char> opt_vec;
int cur = 0;
int len = s.size();
while (i < len && s[i] != ')') {
if (s[i] <= '9' && s[i] >= '0') {
cur = cur * 10 + (s[i++] - '0');
} else if (s[i] == '(') {
cur=f(s,i+1);
i=where+1;
// push(num_vec,opt_vec,cur);
// cur=0;
} else if(s[i]!=' '){
push(num_vec,opt_vec,cur);
cur = 0;
opt_vec.push_back(s[i++]);
}else ++i;
}
//cout<<cur<<endl;
// if(cur)
push(num_vec,opt_vec,cur);
where=i;
return cal(num_vec,opt_vec);
}
int calculate(string s) { return f(s, 0); }
};
二、字符串解码
给定一个经过编码的字符串,返回它解码后的字符串。
编码规则为:
k[encoded_string]
,表示其中方括号内部的encoded_string
正好重复k
次。注意k
保证为正整数。你可以认为输入字符串总是有效的;输入字符串中没有额外的空格,且输入的方括号总是符合格式要求的。
此外,你可以认为原始数据不包含数字,所有的数字只表示重复的次数
k
,例如不会出现像3a
或2[4]
的输入。
思路:
1. 确定递归函数:
- 解码括号内的字符串,并返回解码后的结果
2.大体流程(递归):
遍历字符串,直到遇到尾或‘]’:
- 遇到数字:记录直到遇到括号(与题目一不同,数字后必跟着括号)
- 遇到字母:将其接在答案后
- 遇到'[' :进入递归,根据返回的结果和记录的cnt,处理答案;并利用全局变量where记录递归后要遍历的位置
更新where
代码:
class Solution {
public:
int where;
string f(string s,int i){
int len=s.size();
string ret;
string sub;
int cnt=0;
while(i<len&&s[i]!=']'){
if(s[i]<='z'&&s[i]>='a'){
ret+=s[i++];
}else if(s[i]=='['){
sub=f(s,i+1);
while(cnt--)
{ret+=sub;}
cnt=0;
i=where+1;
}else{
cnt=cnt*10+s[i++]-'0';
}
}
where=i;
return ret;
}
string decodeString(string s) {
return f(s,0);
}
};
三、原子的数量
给你一个字符串化学式
formula
,返回 每种原子的数量 。原子总是以一个大写字母开始,接着跟随 0 个或任意个小写字母,表示原子的名字。
如果数量大于 1,原子后会跟着数字表示原子的数量。如果数量等于 1 则不会跟数字。
- 例如,
"H2O"
和"H2O2"
是可行的,但"H1O2"
这个表达是不可行的。两个化学式连在一起可以构成新的化学式。
- 例如
"H2O2He3Mg4"
也是化学式。由括号括起的化学式并佐以数字(可选择性添加)也是化学式。
- 例如
"(H2O2)"
和"(H2O2)3"
是化学式。返回所有原子的数量,格式为:第一个(按字典序)原子的名字,跟着它的数量(如果数量大于 1),然后是第二个原子的名字(按字典序),跟着它的数量(如果数量大于 1),以此类推。
思路:
1. 确定递归函数:
- 统计括号内的原子数量,并将结果返回到准备的容器中
2.大体流程(递归):
遍历字符串,直到遇到尾或‘)’:
- 遇到数字:利用cnt记录结果
- 遇到字母:若为大写字母,将之前记录的原子和cnt放置在容器中,否则更新原子名
- 遇到'(' :进入递归,在存储返回结果和更新cnt后,处理答案;并利用全局变量where更新处理后要遍历的位置
遍历完后,注意可能的尾部原子遗漏问题(遍历过程中,需要遇到字母才会更新容器)
更新where
代码:
class Solution {
public:
int where;
void f(string& s, int i, unordered_map<string, int>& str_cnt) {
int len = s.size();
string ret;
string sub;
int cnt = 0;
unordered_map<string, int> s_c;
while (i < len && s[i] != ')') {
if (s[i] == '(') {
if (sub != "") {
str_cnt[sub] += cnt == 0 ? 1 : cnt;
sub = "";
cnt = 0;
}
f(s,i+1,s_c);
i= where + 1;
while (i < len && (s[i] <= '9' && s[i] >= '0')) {
cnt = cnt * 10 + s[i++] - '0';
}
for (pair<string, int> kv : s_c) {
str_cnt[kv.first] += kv.second * (cnt == 0 ? 1 : cnt);
}
cnt = 0;
s_c.clear();
} else if (!(s[i] <= '9' && s[i] >= '0')) {
if (s[i] <= 'Z' && s[i] >= 'A' && sub != "") {
str_cnt[sub] += cnt == 0 ? 1 : cnt;
sub = "";
cnt = 0;
}
sub += s[i++];
} else {
while (i < len && (s[i] <= '9' && s[i] >= '0')) {
cnt = cnt * 10 + s[i++] - '0';
}
}
}
if(sub!="")
str_cnt[sub] += cnt == 0 ? 1 : cnt;
where = i;
}
string countOfAtoms(string formula) {
unordered_map<string, int> str_cnt;
map<string, int> cpy;
string ret;
f(formula, 0, str_cnt);
for (pair<string, int> kv : str_cnt) {
cpy[kv.first] = kv.second;
}
for (pair<string, int> kv : cpy) {
ret+=kv.first;
if(kv.second>1)ret+=to_string(kv.second);
}
return ret;
}
};