给你一个字符串化学式 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}。
题解:
/**
* @param {string} formula
* @return {string}
*/
var countOfAtoms = function (formula) {
let i = 0;
const n = formula.length;
const stack = [new Map()];
while (i < n) {
let cur = formula[i]
// 获取原子 => 字母
const parseAtom = () => {
let sub = []
sub.push(formula[i++])
// 扫描字母后面时候有小写字母
if (i < n && formula[i] >= 'a' && formula[i] <= 'z') {
sub.push(formula[i++])
}
return sub.join('')
}
// 获取数字 => 数量
const parseNum = () => {
if (i === n || isNaN(Number(formula[i]))) {
return 1
}
let num = 0;
// 扫描数字
while (i < n && !isNaN(Number(formula[i]))) {
debugger
num = num * 10 + formula[i++].charCodeAt() - '0'.charCodeAt();
}
return num;
}
if (cur == '(') {
i++
// 将一个空的哈希表压入栈中,准备统计括号内的原子数量
stack.unshift(new Map())
} else if (cur == ')') {
i++
// 获取括号右侧数字
const num = parseNum();
// 弹出括号内的原子数量
const popMap = stack.shift();
// 顶层原子数量
const topMap = stack[0];
for (const [atom, v] of popMap.entries()) {
// 将括号内的原子数量乘上 num,加到上一层的原子数量中
topMap.set(atom, (topMap.get(atom) || 0) + v * num);
}
} else {
// 获取原子
const atom = parseAtom();
// 获取数字
const num = parseNum();
const topMap = stack[0];
// 统计原子数量
topMap.set(atom, (topMap.get(atom) || 0) + num);
}
}
// map数据出栈
let map = stack.pop();
// 把map结构转为数组并排序
map = Array.from(map).sort();
const sb = [];
for (const [atom, count] of map) {
sb.push(atom);
if (count > 1) {
// 数字大于1跟随
sb.push(count);
}
}
return sb.join('');
};
来源:力扣(LeetCode)
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。