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)级别。

相关推荐
楚枫默寒3 小时前
Linux 编辑文件后自动添加修改日期
linux·运维·bash
8Qi85 小时前
LeetCode 75:颜色分类(荷兰国旗问题)—— Java 题解 ✅
java·算法·leetcode·指针·排序
2601_961194026 小时前
27考研刘晓艳单词pdf
linux·sql·ubuntu·华为·pdf·.net
888CC++7 小时前
如何在 C 语言中进行程序调试?
前端·javascript·算法
2023自学中7 小时前
imx6ull 开发板 推流ov5640数据,虚拟机用 ffplay 拉流播放
linux·音视频·嵌入式·开发板
shandianchengzi8 小时前
【记录】Ghidra|Ubuntu 26.04 下 Ghidra 界面缩放完整指南
linux·ubuntu·逆向·ghidra
Soari8 小时前
Ubuntu 根分区文件系统损坏,系统启动时自动检查失败
linux·运维·ubuntu
(●—●)橘子……8 小时前
力扣第503场周赛练习理解
python·学习·算法·leetcode·职场和发展·周赛
杨云龙UP8 小时前
Oracle Health Check巡检脚本使用SOP V2.0:从HTML原始报告→生成Word专业巡检报告→交付客户_2026-06-03
linux·运维·数据库·sql·oracle·报告·巡检