### Day14:1.201912-3
#### 1.201912-3:化学方程式(大模拟,字符串解析,嵌套结构处理(括号,用栈))
(1)先获取40分(未处理左右括号)->60分(处理一对括号)->学习满分代码
(2)
##### 1.思路一(不断解析字符串,直到最小单元为化学式,然后来计算):
(1) 对于每个方程式,**`isBalanced`函数将方程式分为左右两部分("="号分割)**,分别调用`parseSide`解析左右两侧的化学式。
(2)**`parseSide`函数负责处理方程式的一侧,它会调用`parseFormula`来解析具体的化学式(“+”号和i<s.size()分割)**。
(3)**`parseFormula`使用栈来处理括号嵌套结构**,通过逐个字符扫描,将化学式中的每个元素及其数量存储到**哈希表**中。
(4) **最后,通过比较左右两边的元素数量**(**比较两个哈希表**),判断是否配平。
(5)代码:
```
#include <bits/stdc++.h>
using namespace std;
//系数字符串转整形,i是引用,自动++
int parseNumber(string s,int &i){
int sum=0;
while(i<s.size() && s[i]>='0' && s[i]<='9'){
sum=sum*10+s[i]-'0';
i++;
}
return sum==0?1:sum;//无系数默认为1(可以变通拓展)
}
//提取一个的化学式的元素及系数(核心)
map<string,int> parseFormula(string s,int qianXi){
map<string,int> res;
stack<map<string,int>> st;
st.push(map<string,int>());//先加一层栈顶
for(int i=0;i<s.size();){
if(s[i]=='('){
//进入新的一层括号
st.push(map<string,int>());
i++;
}
else if(s[i]==')'){
//提取一个层级的map<string,int>,乘上括号后面的系数
i++;
int kuohaoXi=parseNumber(s,i);//这个函数更改i,下面不用i++了
auto top_ele=st.top();//top_ele为map<string,int>和类型
st.pop();//弹出这层,下面的 s.top()为上一层
for(auto &x:top_ele){//x为pair<string,int>类型
st.top()[x.first]+=x.second*kuohaoXi;//改变上一层的<string,int>,加上这一层的<string,int>为这一层每个string的int(下标系数)乘上这一层的括号系数
}
}
else{//处理这一层括号内的单个元素
string ele;
ele+=s[i++];//提取大写字母
while(i<s.size() && s[i]>='a' && s[i]<='z'){
//提取小写字母
ele+=s[i++];
}
int xiaXi=parseNumber(s,i);//提取下标系数
st.top()[ele]+=xiaXi;
}
}
//将栈顶的map乘上前面系数放到res的map里面
for(auto &x:st.top()){
res[x.first]+=x.second*qianXi;
}
return res;
}
//提取一侧的化学方程式的元素及系数
map<string,int> parseSide(string s){
map<string,int> res;
for(int i=0;i<s.size();){
int qianXi=parseNumber(s,i);//获取前面系数
int start=i;//一个化学式的开始
while(i<s.size() && s[i]!='+') i++;//+分隔一个化学式
auto formula_ele=parseFormula(s.substr(start,i-start),qianXi);//解析一个化学式,获取元素哈希表
//把每一个化学式哈希表加入一侧方程式哈希表中
for(auto x:formula_ele){
res[x.first]+=x.second;
}
i++;//跳过+号
}
return res;
}
//判断左右两个化学方程式是否相等
bool isBalanced(string s){
auto pos=s.find('=');//通过"="号划分
string left=s.substr(0,pos);
string right=s.substr(pos+1);
auto left_ele=parseSide(left);//解析一测方程式
auto right_ele=parseSide(right);
return left_ele==right_ele;
}
int main(){
int n;
cin>>n;
while(n--){
string s;
cin>>s;
cout<<(isBalanced(s)?"Y":"N")<<endl;
}
return 0;
}
```
(6)栈使用核心(括号嵌套):
1.确定栈的元素,本题为map<string,int>,表示当前括号内的元素和数量
2.初始化栈并添加一个栈顶
3.确定何时压入一个栈元素并相应操作:遇到'('压入一个新的map<string,int>,表示这一个括号内的元素和数量
4.确定何时弹出一个栈元素并相应操作:遇到')'弹出这一个括号内的map<string,int>,获取上一个括号内的map<string,int>(即为top()),加上这一个括号内的元素下标系数乘以算得的括号系数
5.处理一个括号内的栈元素,大写字母+小写字母+小标系数=一个化学式,存入当map<string,int>中
6.最后栈顶元素为这一个方程式的map<string,int>,但不包括前面的系数,所以结果map<string,int>为栈顶的map<string,int>乘上传入的前面系数
```
//提取一个的化学式的元素及系数(核心)
map<string,int> parseFormula(string s,int qianXi){
map<string,int> res;
stack<map<string,int>> st;
st.push(map<string,int>());//先加一层栈顶
for(int i=0;i<s.size();){
if(s[i]=='('){
//进入新的一层括号
st.push(map<string,int>());
i++;
}
else if(s[i]==')'){
//提取一个层级的map<string,int>,乘上括号后面的系数
i++;
int kuohaoXi=parseNumber(s,i);//这个函数更改i,下面不用i++了
auto top_ele=st.top();//top_ele为map<string,int>和类型
st.pop();//弹出这层,下面的 s.top()为上一层
for(auto &x:top_ele){//x为pair<string,int>类型
st.top()[x.first]+=x.second*kuohaoXi;//改变上一层的<string,int>,加上这一层的<string,int>为这一层每个string的int(下标系数)乘上这一层的括号系数
}
}
else{//处理这一层括号内的单个元素
string ele;
ele+=s[i++];//提取大写字母
while(i<s.size() && s[i]>='a' && s[i]<='z'){
//提取小写字母
ele+=s[i++];
}
int xiaXi=parseNumber(s,i);//提取下标系数
st.top()[ele]+=xiaXi;
}
}
//将栈顶的map乘上前面系数放到res的map里面
for(auto &x:st.top()){
res[x.first]+=x.second*qianXi;
}
return res;
}
```