LeetCode 原子的数量(递归+hash表)

版权声明:本文为博主原创文章,博客地址:https://blog.csdn.net/qq_41855420,未经博主允许不得转载。 https://blog.csdn.net/qq_41855420/article/details/89644525

给定一个化学式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只包含字母、数字和圆括号,并且题目中给定的是合法的化学式。

思路分析: 这显然是一道递归处理的题,比如处理 “K4(ON(SO3)2)2”,我们先从左到右处理处理,遇到左括号,则递归处理括号内部的,然后回归的时候将括号内的各个元素出现的次数乘上括号外部的值。然后继续扫描剩余的部分。

第一种情况:遇到了左括号,递归处理括号内部的
第二种情况:遇到了右括号,则返回下一个下标比如"Mg(OH)2",应该返回'2'的下标
第三种情况:遇到普通原子,先读取原子的名称,然后读取该原子的倍率
class Solution {
public:
	string countOfAtoms(string formula) {
		string resStr = "";
		map<string, int> hashMap;//用于统计各个原子出现的次数(已经按照字典升序排序)
		myFunc(formula, 0, hashMap);//从起始开始处理formula
        //最后将得到的结果进行合并成字符串
		for (auto &item : hashMap) {
			resStr += item.first;
			if (item.second > 1) {//只有当这个元素出现多次时才需要加上倍数,比如"H2O"中的O只出现了一次,所以不需要倍数
				resStr += to_string(item.second);
			}
		}
		return resStr;
	}
    //从formula[nowIndex]开始处理剩余的化学式,返回处理后剩余的起始下标
	int myFunc(string &formula, int nowIndex, map<string, int> &hashMap) {
		int formulaSize = formula.size();
		if (nowIndex >= formulaSize || formula[nowIndex] == ')') {
			return nowIndex + 1;
		}
		while (nowIndex < formulaSize) {
			if (formula[nowIndex] == '(') {
                //第一种情况:遇到了左括号,递归处理括号内部的
				map<string, int> tempMap;//统计括号内部各个原子出现的次数
				nowIndex = myFunc(formula, nowIndex + 1, tempMap);//返回的是当前左括号匹配的右括号后面的第一个字符位置
                //计算右括号后的倍率,如"Mg(OH)2"中“(OH)”后的数字2
				int cnt = 0;
				while (nowIndex < formulaSize && formula[nowIndex] >= '0' && formula[nowIndex] <= '9') {
					cnt = cnt * 10 + formula[nowIndex++] - '0';
				}
                //如果出现倍率,则需要先放大,否则默认是1不处理
				if (cnt > 0) {
					for (auto &item : tempMap) {
						item.second *= cnt;
					}
				}
                //将括号中各个原子的个数合并到当前hashMap中
				for (auto &item : tempMap) {
					hashMap[item.first] += item.second;
				}
			}
			else if (formula[nowIndex] == ')') {
                //第二种情况:遇到了右括号,则返回下一个下标比如"Mg(OH)2",应该返回'2'的下标
				return nowIndex + 1;
			}
			else {
                //第三种情况:遇到普通原子
                //先读取原子的名称(所有原子的第一个字母为大写,剩余字母都是小写。),也就是说以大写字母分割原子名称
				string name = string(1, formula[nowIndex++]);
				while (nowIndex < formulaSize && formula[nowIndex] >= 'a' && formula[nowIndex] <= 'z') {
					name += formula[nowIndex++];
				}
                //然后读取该原子的倍率
				int cnt = 0;
				while (nowIndex < formulaSize && formula[nowIndex] >= '0' && formula[nowIndex] <= '9') {
					cnt = cnt * 10 + formula[nowIndex++] - '0';
				}
				if (cnt > 0) {//倍数超过了1需要放大
					hashMap[name] += (cnt);
				}
				else {//否则默认是1
					hashMap[name] += 1;
				}
			}
		}
		return nowIndex;
	}
};

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_41855420/article/details/89644525
今日推荐