哈希表题目:原子的数量

这篇具有很好参考价值的文章主要介绍了哈希表题目:原子的数量。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

题目

标题和出处

标题:原子的数量

出处:726. 原子的数量

难度

8 级

题目描述

要求

给你一个表示化学式的字符串 formula \texttt{formula} formula,返回每种原子的数量。

原子总是以一个大写字母开始,跟随零个或任意个小写字母,表示原子的名字。

如果数量大于 1 \texttt{1} 1,原子后会跟着数字表示原子的数量。如果数量等于 1 \texttt{1} 1 则不会跟数字。

  • 例如, "H2O" \texttt{"H2O"} "H2O" "H2O2" \texttt{"H2O2"} "H2O2" 是可行的,但 "H1O2" \texttt{"H1O2"} "H1O2" 是不可行的。

两个化学式连在一起可以构成新的化学式。

  • 例如, "H2O2He3Mg4" \texttt{"H2O2He3Mg4"} "H2O2He3Mg4" 也是化学式。

由括号包含的化学式并佐以数字(可选择性添加)也是化学式。

  • 例如, "(H2O2)" \texttt{"(H2O2)"} "(H2O2)" "(H2O2)3" \texttt{"(H2O2)3"} "(H2O2)3" 是化学式。

返回所有原子的数量,格式为:第一个(按字典序)原子的名字,跟着它的数量(如果数量大于 1 \texttt{1} 1),然后是第二个原子的名字(按字典序),跟着它的数量(如果数量大于 1 \texttt{1} 1),以此类推。

题目保证输出的所有值都在 32 \texttt{32} 32 位整数范围内。

示例

示例 1:

输入: formula   =   "H2O" \texttt{formula = "H2O"} formula = "H2O"
输出: "H2O" \texttt{"H2O"} "H2O"
解释:原子的数量是 {‘H’:   2,   ‘O’:   1} \texttt{\{`H': 2, `O': 1\}} {‘H’: 2, ‘O’: 1}

示例 2:

输入: formula   =   "Mg(OH)2" \texttt{formula = "Mg(OH)2"} formula = "Mg(OH)2"
输出: "H2MgO2" \texttt{"H2MgO2"} "H2MgO2"
解释:原子的数量是 {‘H’:   2,   ‘Mg’:   1,   ‘O’:   2} \texttt{\{`H': 2, `Mg': 1, `O': 2\}} {‘H’: 2, ‘Mg’: 1, ‘O’: 2}

示例 3:

输入: formula   =   "K4(ON(SO3)2)2" \texttt{formula = "K4(ON(SO3)2)2"} formula = "K4(ON(SO3)2)2"
输出: "K4N2O14S4" \texttt{"K4N2O14S4"} "K4N2O14S4"
解释:原子的数量是 {‘K’:   4,   ‘N’:   2,   ‘O’:   14,   ‘S’:   4} \texttt{\{`K': 4, `N': 2, `O': 14, `S': 4\}} {‘K’: 4, ‘N’: 2, ‘O’: 14, ‘S’: 4}

数据范围

  • 1 ≤ formula.length ≤ 1000 \texttt{1} \le \texttt{formula.length} \le \texttt{1000} 1formula.length1000
  • formula \texttt{formula} formula 由英语字母、数字、 ‘(’ \texttt{`('} ‘(’ ‘)’ \texttt{`)'} ‘)’ 组成
  • formula \texttt{formula} formula 总是有效的化学式

解法

思路和算法

这道题需要使用到哈希表和栈这两种数据结构,哈希表用于记录每种原子的数量,栈用于处理化学式中的括号嵌套。栈内存储哈希表,哈希表用于记录当前层中每种原子的数量。将最外层(即整个化学式)记为第 1 1 1 层,从左到右遍历化学式,每遇到一个左括号则将层数加 1 1 1,每遇到一个右括号则将层数减 1 1 1,在任意时刻,栈内的哈希表个数等于当前遍历到的层数编号。

在遍历化学式之前,首先将一个空哈希表入栈,该哈希表用于记录整个化学式中每种原子的数量。从左到右遍历化学式的过程中,需要将化学式的每个成分分离,并对每个成分执行相应的操作。化学式中的成分包括以下四种:

  • 原子,为一个或多个连续的字母,第一个字母是大写,其余字母都是小写;
  • 原子或原子团的数量,为一个或多个连续的数字;
  • 左括号,表示原子团的开始;
  • 右括号,表示原子团的结束。

上述四种成分中,数量一定出现在一个原子或者一个原子团的后面,因此在处理完一个原子或者一个原子团之后即可处理数量,不需要单独处理数量。对于其余三种成分,需要在遍历过程中处理。

  • 如果遇到大写字母,则是一个原子的开始,执行如下操作。

    1. 继续遍历后面的字符,直到遍历到化学式末尾或者遇到的字符不是小写字母,此时得到原子名。

    2. 如果原子名的后面是数字,则继续遍历后面的字符,直到遍历到化学式末尾或者遇到的字符不是数字,此时得到原子的当前数量。如果原子名的后面不是数字,则当前数量为 1 1 1

    3. 从栈顶获得当前层的哈希表,在当前层的哈希表中将该原子的数量增加当前数量。

  • 如果遇到左括号,则是一个原子团的开始,进入下一层,因此将一个空的哈希表入栈。

  • 如果遇到右括号,则是一个原子团的结束,回到上一层,执行如下操作。

    1. 如果原子团的后面是数字,则继续遍历后面的字符,直到遍历到化学式末尾或者遇到的字符不是数字,此时得到原子团的数量。如果原子团的后面不是数字,则原子团的数量为 1 1 1

    2. 将原子团所在层的哈希表出栈,该哈希表称为原子团哈希表,该哈希表出栈之后位于栈顶的哈希表称为栈顶哈希表。

    3. 遍历原子团哈希表,对于原子团哈希表中的每个原子,其当前数量为哈希表中的数量乘以原子团的数量,在栈顶哈希表中将原子的数量增加当前数量。

遍历结束之后,栈内只剩下一个哈希表,将该哈希表出栈,该哈希表记录整个化学式中每种原子的数量。

由于返回所有原子的数量的格式要求是按照原子名的字典序排序,因此需要按照字典序依次遍历哈希表中的所有原子名,并将原子名和对应的原子数量拼接到结果中。排序的方法有多种,此处提供的解法使用优先队列存储哈希表中的所有原子名,优先队列的队首元素是字典序最小的原子名。

每次从优先队列中取出字典序最小的原子名,然后从哈希表中得到对应的原子数量,将原子名和原子数量拼接到结果中(如果原子数量是 1 1 1 则原子数量不拼接到结果中)。当优先队列为空时,所有的原子名和原子数量都加入到结果中。

代码

class Solution {
    public String countOfAtoms(String formula) {
        Deque<Map<String, Integer>> stack = new ArrayDeque<Map<String, Integer>>();
        stack.push(new HashMap<String, Integer>());
        int length = formula.length();
        int index = 0;
        while (index < length) {
            char c = formula.charAt(index);
            index++;
            if (Character.isUpperCase(c)) {
                StringBuffer temp = new StringBuffer();
                temp.append(c);
                while (index < length && Character.isLowerCase(formula.charAt(index))) {
                    temp.append(formula.charAt(index));
                    index++;
                }
                String atom = temp.toString();
                int count = 0;
                while (index < length && Character.isDigit(formula.charAt(index))) {
                    int digit = formula.charAt(index) - '0';
                    count = count * 10 + digit;
                    index++;
                }
                if (count == 0) {
                    count = 1;
                }
                Map<String, Integer> map = stack.peek();
                map.put(atom, map.getOrDefault(atom, 0) + count);
            } else if (c == '(') {
                stack.push(new HashMap<String, Integer>());
            } else {
                int multiple = 0;
                while (index < length && Character.isDigit(formula.charAt(index))) {
                    int digit = formula.charAt(index) - '0';
                    multiple = multiple * 10 + digit;
                    index++;
                }
                if (multiple == 0) {
                    multiple = 1;
                }
                Map<String, Integer> tempMap = stack.pop();
                Map<String, Integer> map = stack.peek();
                Set<Map.Entry<String, Integer>> entries = tempMap.entrySet();
                for (Map.Entry<String, Integer> entry : entries) {
                    String atom = entry.getKey();
                    int count = entry.getValue() * multiple;
                    map.put(atom, map.getOrDefault(atom, 0) + count);
                }
            }
        }
        Map<String, Integer> map = stack.pop();
        PriorityQueue<String> pq = new PriorityQueue<String>(map.keySet());
        StringBuffer output = new StringBuffer();
        while (!pq.isEmpty()) {
            String atom = pq.poll();
            int count = map.get(atom);
            output.append(atom);
            if (count > 1) {
                output.append(count);
            }
        }
        return output.toString();
    }
}

复杂度分析

  • 时间复杂度: O ( n 2 ) O(n^2) O(n2),其中 n n n 是字符串 formula \textit{formula} formula 的长度。
    栈内最多有 O ( n ) O(n) O(n) 层,每次出栈最多需要更新 O ( n ) O(n) O(n) 个原子的数量,因此计算每个原子的数量需要 O ( n 2 ) O(n^2) O(n2) 的时间。
    拼接结果时,优先队列中的元素个数是 O ( n ) O(n) O(n),共需要 O ( n log ⁡ n ) O(n \log n) O(nlogn) 的时间拼接结果。
    因此总时间复杂度是 O ( n 2 + n log ⁡ n ) = O ( n 2 ) O(n^2 + n \log n) = O(n^2) O(n2+nlogn)=O(n2)

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是字符串 formula \textit{formula} formula 的长度。空间复杂度取决于栈内所有哈希表中的元素个数之和,以及优先队列中的元素个数,由于哈希表中的元素个数之和以及优先队列中的元素个数不会超过化学式的长度,因此空间复杂度是 O ( n ) O(n) O(n)文章来源地址https://www.toymoban.com/news/detail-463592.html

到了这里,关于哈希表题目:原子的数量的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • leetcode 哈希表相关题目

    题目:https://leetcode.cn/problems/valid-anagram/description/ 题解:https://leetcode.cn/problems/valid-anagram/solutions/2602947/shu-zu-ha-xi-biao-tong-ji-mei-ge-zi-mu-c-vhh5/ 题目:https://leetcode.cn/problems/intersection-of-two-arrays/description/ 题解:https://leetcode.cn/problems/intersection-of-two-arrays/solutions/2603171/jie-guo-shu-zu-un

    2024年01月21日
    浏览(40)
  • 哈希表C++哈希表详解(知识点+相关LeetCode题目)

    目录 前言 一、什么是哈希表 二、哈希表的操作 2.1 操作时间复杂度 2.2 哈希表通用API 2.3 建立哈希表 2.3 哈希表常见结构介绍 Set(集合) Map(映射) unordered_map(哈希表) 三、哈希表的力扣经典题目 有效的字母异位词242 两个数组的交集 349 两数之和1 四数相加II 454 三数之和

    2024年03月20日
    浏览(47)
  • 哈希表题目:TinyURL 的加密与解密

    标题:TinyURL 的加密与解密 出处:535. TinyURL 的加密与解密 7 级 要求 TinyURL 是一种 URL 简化服务。当你输入一个 URL,例如 https://leetcode.com/problems/design-tinyurl 时,它将返回一个简化的 URL,例如 http://tinyurl.com/4e9iAk 。设计一个类对 URL 加密和对 TinyURL 解密。 你的加密和解密算法如

    2024年02月04日
    浏览(36)
  • 全面理解哈希,哈希的底层原理是如何实现的,哈希题型的做题思路与题目清单(不断更新)

    哈希(Hash)是一种算法,它接受一个输入(或“消息”),并返回一个固定大小的字符串。这个输出字符串的大小通常以字节为单位,输出的内容看起来是随机的且整个过程是单向的。 哈希的一些关键特性包括: 不管你输入的信息有多大,哈希值的大小总是固定的。 即使只

    2024年02月04日
    浏览(45)
  • 必刷算法题之哈希篇(题目及代码)---C++

    解法1 :(对于大规模数据,时间和空间复杂度会超出) 解题思路如下: 假设第一个数为a,用目标值c减去第一个数a,得到b,然后遍历后面的数,查看b是否在后面的数组中 解法2 :(利用哈希表) 解法1 :(排序) 由于多数元素是指在数组中出现次数大于 【n/2】 的元素,

    2023年04月18日
    浏览(36)
  • C#从入门到入坟(不易,转载请注明出处)

    安装Visual Studio。 下载地址:https://visualstudio.microsoft.com/zh-hans/ 可以选择社区版本,是可以免费使用的。 下载之后配置安装。 按照自己的工作需要,勾选相应的组件和安装位置,进行安装即可。 目前C#开发的两种框架 运行于windows的.Net Framework 可以跨平台的.Net6 项目名称 建议

    2024年02月05日
    浏览(43)
  • stable-diffusion-webui的基础功能手动安装,了解代码结构、依赖、模型出处

    Stable Diffusion `一键安装包( 解压即用 防爆显存 ):https://www.bilibili.com/video/BV1iM4y1y7oA/ 相关博文: 1.stable-diffusion-webui安装(2):扩展模块extensions——汉化、双语等 2. stable-diffusion 训练GUI安装——lora、dreambooth 虽然,当前 B站 有很多stable-diffusion-webui 的一键安装包,但是不易

    2024年01月19日
    浏览(59)
  • 《JUC并发编程 - 高级篇》05 -共享模型之无锁 (CAS | 原子整数 | 原子引用 | 原子数组 | 字段更新器 | 原子累加器 | Unsafe类 )

    有如下需求,保证 account.withdraw 取款方法的线程安全 原有实现并不是线程安全的 测试代码 执行测试代码,某次执行结果 5.1.1 为么不安全 withdraw 方法是临界区,会存在线程安全问题 查看下字节码 多线程在执行过程中可能会出现指令的交错,从而结果错误! 5.1.2 解决思路1

    2023年04月12日
    浏览(45)
  • 图论第二天|岛屿数量.深搜版、岛屿数量.广搜版、岛屿的最大面积、1020.飞地的数量

    文档讲解 :代码随想录 - 岛屿数量.深搜版 状态:开始学习。 本题是dfs模板题 本题代码: 文档讲解 :代码随想录 - 岛屿数量.广搜版 状态:开始学习。 思路:bfs模板题 本题代码: 文档讲解 :代码随想录 - 岛屿的最大面积 状态:开始学习。 思路: 这道题目也是 dfs bfs 基础

    2024年02月08日
    浏览(40)
  • Python matplotlib 画图 设置标题 大标题 副标题 大小、位置、粗细全集

    设置标题大小、字体、位置、字体粗细、斜体(二级) 设置大标题 suptitle 标题大小、字体、位置、字体粗细、斜体(一级)

    2024年02月13日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包