- 原子的数量
给定一个化学式formula(作为字符串),返回每种原子的数量。
原子总是以一个大写字母开始,接着跟随0个或任意个小写字母,表示原子的名字。
如果数量大于 1,原子后会跟着数字表示原子的数量。如果数量等于 1 则不会跟数字。例如,H2O 和 H2O2 是可行的,但 H1O2 这个表达是不可行的。
两个化学式连在一起是新的化学式。例如 H2O2He3Mg4 也是化学式。
一个括号中的化学式和数字(可选择性添加)也是化学式。例如 (H2O2) 和 (H2O2)3 是化学式。
给定一个化学式,输出所有原子的数量。格式为:第一个(按字典序)原子的名子,跟着它的数量(如果数量大于 1),然后是第二个原子的名字(按字典序),跟着它的数量(如果数量大于 1),以此类推。
示例 1:
输入:
formula = “H2O”
输出: “H2O”
解释:
原子的数量是 {‘H’: 2, ‘O’: 1}。
示例 2:
输入:
formula = “Mg(OH)2”
输出: “H2MgO2”
解释:
原子的数量是 {‘H’: 2, ‘Mg’: 1, ‘O’: 2}。
示例 3:
输入:
formula = “K4(ON(SO3)2)2”
输出: “K4N2O14S4”
解释:
原子的数量是 {‘K’: 4, ‘N’: 2, ‘O’: 14, ‘S’: 4}。
注意:
所有原子的第一个字母为大写,剩余字母都是小写。
formula的长度在[1, 1000]之间。
formula只包含字母、数字和圆括号,并且题目中给定的是合法的化学式。
题解
利用栈匹配,然后主要麻烦两个地方,括号和括号后面跟了数字的情况比如(H2O)2。
利用括号匹配把层层嵌套的括号内容打开,不难,针对这种H2O比较裸的字符串直接单独写个函数处理,然后此时要特判后面有没有数字,有的话就把数字加进去处理成一个最终 的字符串再返回来,进行新的括号匹配。
AC代码
class Solution {
public:
typedef long long ll;
struct Node
{
string val;
ll ans;
};
string int_to_str(ll x)
{
if(x==1)return "";
string s="";
while(x>0)
{
s+=(x%10+'0');
x/=10;
}
reverse(s.begin(),s.end());
return s;
}
Node solve(string s)//用来解析每个单个的H2或O2的情况,以结构体返回原子名字和对应的数字
{
Node t;
t.val="",t.ans=0;
int i;
for(i=0;i<s.length();i++)
{
if(s[i]>='0'&&s[i]<='9')
break;
t.val+=s[i];
}
for(;i<s.length();i++)
{
t.ans*=10;
t.ans+=(s[i]-'0');
}
if(t.ans==0)t.ans=1;
return t;
}
static int cmp(Node a1,Node a2)//排序函数
{
return a1.val<a2.val;
}
string fun(string s,int ans)//用来处理没有括号的字符串,比如H2O
{
reverse(s.begin(),s.end());
vector<string>q;
string t="";
for(int i=0;i<s.length();i++)//把每个单独的原子拆出来
{
if(i>0&&s[i]>='A'&&s[i]<='Z')
{
q.push_back(t);
t="";
t+=s[i];
}
else t+=s[i];
}
if(t!="")
q.push_back(t);
vector<Node>res;
for(int i=0;i<q.size();i++)
{
res.push_back(solve(q[i]));//把处理后的结果加进来
}
sort(res.begin(),res.end(),cmp);//按原子名字字典序排序
vector<Node>fin;
fin.push_back(res[0]);
for(int i=1;i<res.size();i++)//这里是把相同原子名的组合起来,比如CO2H3O4这种,把O组合起来
{
int n=fin.size();
if(fin[n-1].val==res[i].val)//判断原子名相同就组合
fin[n-1].ans+=res[i].ans;
else
fin.push_back(res[i]);
}
if(ans>0)//ans大于0,说明数目要累乘
{
for(int i=0;i<fin.size();i++)
fin[i].ans*=ans;
}
string answer="";
for(int i=0;i<fin.size();i++)//又把数字转换成字符串,返回答案
answer+=(fin[i].val+int_to_str(fin[i].ans));
return answer;
}
stack<char>q;
string countOfAtoms(string formula)
{
formula="("+formula+")";
string answer="";
for(int i=0;i<formula.length();i++)
{
if(formula[i]==')')
{
string s="";
while(q.empty()==false&&q.top()!='(')
{
s+=q.top();
q.pop();
}
q.pop();
//if(s=="")continue;
ll ans=0;
if(formula[i+1]>='0'&&formula[i+1]<='9')//特判数字
{
for(int j=i+1;j<formula.length();j++)
{
if(formula[j]<'0'||formula[j]>'9')
{
i=j-1;
break;
}
ans*=10;
ans+=(formula[j]-'0');
}
}
answer=fun(s,ans);
for(int j=0;j<answer.length();j++)//装入栈内,进行新的处理
q.push(answer[j]);
}
else q.push(formula[i]);
}
return answer;
}
};