一、题目描述:726. 原子的数量(困难)
给定一个化学式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只包含字母、数字和圆括号,并且题目中给定的是合法的化学式。来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/number-of-atoms
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
二、解题思路
1、由于存在括号,所有使用栈 vector<pair<string>,int> stack来保存每个原子的数量。遍历字符串如果是原子,则计算原子个数并且入栈;当遇到'('的时候也入栈;当遇到’)‘的时候,计算括号后面的个数num_tmp,然后stack往回走,每个原子出栈并且原子个数乘以num_tmp,将其存在另外一个容器stack_tmp中。直到stack遇到’(‘和’)‘匹配上了,这时候stack删除’(’。然后将stack_tmp放回到stack中。字符串继续往前遍历。
2、当遍历完字符串之后,所有的原子都去除括号存在stack中了。这时候使用一个map save_icron去重累加所有的原子的个数
3、由于map自带字典序排序功能。所以遍历完stack,save_icron累加完所有原子个数之后。直接遍历save_icron将原子和原子个数序列化到字符串中(当原子个数为1的时候,不输出原子个数)。
三、代码
class Solution {
public:
string countOfAtoms(string formula) {
vector<pair<string,int>> stack;
int left = 0;
int right = 0;
for(int i = 0; i < formula.size();)
{
if(formula[i] >= 'A' && formula[i] <= 'Z')
{
left = i;
int j = i+1;
while(j < formula.size() && formula[j] >='a' && formula[j] <= 'z')
{
j++;
}
string icron = formula.substr(i,j-i);
if(j < formula.size() && formula[j] >= '0' && formula[j] <= '9')
{
int num = j;
while(num < formula.size() && formula[num] >= '0' && formula[num] <= '9')
{
num++;
}
int num_icron = atoi(formula.substr(j,num-j).c_str());
stack.push_back(make_pair(icron,num_icron));
i = num;
}
else
{
stack.push_back(make_pair(icron,1));
i = j;
}
}
else if(formula[i] == '(')
{
stack.push_back(make_pair(formula.substr(i,1),1));
i++;
}
else if(formula[i] == ')')
{
int j = i+1;
if(j < formula.size() && formula[j] >='0' && formula[j] <= '9')
{
int num = j+1;
while(num < formula.size() && formula[num] >='0' && formula[num] <= '9')
{
num++;
}
int num_cron = atoi(formula.substr(j,num-j).c_str());
vector<pair<string,int>> save_tmp;
while(stack.size() > 0 && stack.rbegin()->first != "(")
{
stack.rbegin()->second = stack.rbegin()->second * num_cron;
save_tmp.push_back(*stack.rbegin());
stack.pop_back();
}
if(stack.size() >0)
stack.pop_back();
stack.insert(stack.end(),save_tmp.begin(),save_tmp.end());
i = num;
}
}
}
map<string,int> save_icon;
for(int i = 0; i < stack.size(); i++)
{
if(save_icon.count(stack[i].first) == 0)
{
save_icon[stack[i].first] = stack[i].second;
}
else
{
save_icon[stack[i].first] += stack[i].second;
}
}
string out;
for(map<string,int>::iterator it = save_icon.begin(); it != save_icon.end(); it++)
{
out.append(it->first);
if(it->second > 1)
out.append(to_string(it->second));
}
return out;
}
};