给定一个化学式formula
(作为字符串),返回每种原子的数量。
原子总是以一个大写字母开始,接着跟随0个或任意个小写字母,表示原子的名字。
如果数量大于1,原子后会跟着数字表示原子的数量。如果数量等于1则不会跟数字。例如,H2O和H2O2是可行的,但H1O2这个表达是不可行的。
两个化学式连在一起是新的化学式。例如H2O2He3Mg4也是化学式。
一个括号中的化学式和数字(可选择性添加)也是化学式。例如(H2O2)和(H2O2)3是化学式。
给定一个化学式,输出所有原子的数量。格式为:第一个(按字典序)原子的名子,跟着它的数量(如果数量大于1),然后是第二个原子的名字(按字典序),跟着它的数量(如果数量大于1),以此类推。
示例1:
输入: 公式=“H2O” 输出: “H2O” 解释: 原子的数量是{'H':2,'O':1}。
示例2:
输入: 公式=“Mg(OH)2” 输出: “H2MgO2” 解释: 原子的数量是{'H':2,'Mg':1,'O':2}。
示例3:
输入: 公式=“K4(ON(SO3)2)2” 输出: “K4N2O14S4” 解释: 原子的数量是{'K':4,'N':2,'O':14,'S':4}。
注意:
- 所有原子的第一个字母为大写,剩余字母都是小写。
formula
长度的在[1, 1000]
之间。formula
只包含字母,数字和圆括号,并且题目中给定的是合法的化学式。
思路:
- 顺次遍历字符串
- 碰到左括号进入递归,处理括号内的内容,得到的返回结果的每个元素数量,加在该层的结果中
- 碰到右括号,获取括号后紧跟着的数字,并将该层的结果的每个元素数量,都乘以这个数,返回结果
- 如果是其他,顺次遍历,碰到大写直到碰到不是小写字母结束,为一个元素,数量为之后紧跟的数,存在该元素就加入该层的结果中,没有就添加该元素
class Solution {
public:
string countOfAtoms(string formula) {
// 碰到左括号进入递归,碰到右括号返回
int pos = 0;
map<string, int> m;
parse(formula, pos, m);
string result;
for (pair<string, int> a : m)
result += a.first + (a.second == 1 ? "" : to_string(a.second));
return result;
}
void parse(string& formula, int& pos, map<string, int>& result)
{
while (pos < formula.size())
{
if (formula[pos] == '(')
{
++pos;
map<string, int> temp;
parse(formula, pos, temp);
for (pair<string, int> a : temp)
result[a.first] += a.second;
}
else if (formula[pos] == ')')
{
++pos;
int i = pos;
while (pos < formula.size() && isdigit(formula[pos]))
pos++;
// 将括号后面紧跟的数字获取
string multipleString = formula.substr(i, pos - i);
int multiple = multipleString.empty() ? 1 : stoi(multipleString);
for (pair<string, int> a : result)
result[a.first] *= multiple;
return;
}
else
{
int i = pos++;
while (pos < formula.size() && islower(formula[pos]))
pos++;
// 获取元素
string element = formula.substr(i, pos - i);
i = pos;
while (pos < formula.size() && isdigit(formula[pos]))
pos++;
// 将元素后面紧跟的数字获取
string count = formula.substr(i, pos - i);
result[element] += count.empty() ? 1 : stoi(count);
}
}
}
};