LeetCode 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}。

提示:

1 <= formula.length <= 1000

formula 由英文字母、数字、'(' 和 ')' 组成

formula 总是有效的化学式

递归处理,遇到括号压栈,括号结束出栈,并计算括号内的原子数:

cpp 复制代码
class Solution {
public:
    string countOfAtoms(string formula) {
        stack<map<string, int>> stk;
        
        map<string, int> curCnt;
        string curName = "";
        int curNum = 0;
        for (int i = 0; i < formula.size(); ++i) {
            char c = formula[i];

            // 遇到新的元素,或遇到括号时,说明处理完一个元素了
            if (isupper(c) || c == '(' || c == ')') {
                // 将得到的元素和数量计入答案
                if (!curName.empty()) {
                    curNum = max(1, curNum);

                    curCnt[curName] += curNum;
                }

                curName = "";
                curNum = 0;
            }

            // 遇到左括号,入栈当前层的原子及其数量
            if (c == '(') {
                stk.push(curCnt);
                curCnt.clear();
            }

            // 遇到右括号
            if (c == ')') {
                // 看括号内的集合会重复几次
                ++i;
                int num = 0;
                while (i < formula.size() && isdigit(formula[i])) {
                    num = num * 10 + (formula[i] - '0');
                    ++i;
                }
                num = max(num, 1);

                // 括号内的原子数量重复num次
                for (auto &p : curCnt) {
                    p.second *= num;
                }

                // 上一层的原子数量也加到结果里
                for (auto &p : stk.top()) {
                    curCnt[p.first] += p.second * num;
                }

                stk.pop();

                --i;
            }

            if (isalpha(c)) {
                curName.push_back(c);
            } else if (isdigit(c)) {
                curNum = curNum * 10 + (c - '0');
            }

            if (i == formula.size() - 1) {
                if (!curName.empty()) {
                    curNum = max(1, curNum);

                    curCnt[curName] += curNum;
                }
            }
        }

        string res;
        for (auto p : curCnt) {
            res += p.first;
            if (p.second != 1) {
                res += to_string(p.second);
            }
        }

        return res;
    }
};

如果formula的长度为n,则此算法时间复杂度为O(n2^22),首先遍历formula的时间是n,最差情况下,即尽可能多层嵌套时,如(B(C(D)n1)n2)n3,此时curCnt最多只会有一个原子,出栈时也只会有1个原子,但出栈阶段curCnt会线性增长到O(n)级别,每次出栈都会遍历curCnt,让curCnt的每个原子重复括号后的数字次,因此内层循环也需要O(n)时间;空间复杂度为O(n),因为stk的最大深度是O(n)级别。

相关推荐
君义_noip1 小时前
CSP-S 2025 提高级 第一轮(初赛) 阅读程序(3)
c++·算法·信息学奥赛·csp-s 初赛
剑神一笑1 小时前
Linux tree 命令深度解析:从目录遍历到树形可视化的完整实现
linux·运维·elasticsearch
玛卡巴卡ldf1 小时前
【LeetCode 手撕算法】(栈)有效括号、最小栈、字符串解码、每日温度、柱状图最大矩形
java·数据结构·算法·leetcode·力扣
happyprince1 小时前
05-FlagEmbedding 评估模块详解
算法
wuweijianlove1 小时前
算法优化的多目标平衡与性能建模研究的技术7
算法
_深海凉_1 小时前
LeetCode热题100-两两交换链表中的节点
算法·leetcode·链表
啊罗罗1 小时前
windows下,c++的axv2+fma/avx-vnni加速计算demo
c++·windows·算法
qq_283720051 小时前
Embedding 调优实战技巧:从原理到落地,打造高精度向量检索
python·算法·词嵌入·调优
Xpower 171 小时前
OpenClaw近一月版本更替讲解
人工智能·学习·算法