From adb6b42e6179a59102fbe55fd6a9e1089faf11fa Mon Sep 17 00:00:00 2001 From: AC_Oier Date: Mon, 5 Jul 2021 11:01:49 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8feat:=20Add=20726?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../\345\223\210\345\270\214\350\241\250.md" | 1 + "Index/\345\240\206.md" | 1 + "Index/\346\240\210.md" | 1 + "Index/\346\250\241\346\213\237.md" | 1 + ...10\345\233\260\351\232\276\357\274\211.md" | 188 ++++++++++++++++++ 5 files changed, 192 insertions(+) create mode 100644 "LeetCode/721-730/726. \345\216\237\345\255\220\347\232\204\346\225\260\351\207\217\357\274\210\345\233\260\351\232\276\357\274\211.md" diff --git "a/Index/\345\223\210\345\270\214\350\241\250.md" "b/Index/\345\223\210\345\270\214\350\241\250.md" index 8ec64a28..15665924 100644 --- "a/Index/\345\223\210\345\270\214\350\241\250.md" +++ "b/Index/\345\223\210\345\270\214\350\241\250.md" @@ -16,6 +16,7 @@ | [697. 数组的度](https://leetcode-cn.com/problems/degree-of-an-array/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/degree-of-an-array/solution/shu-zu-ji-shu-ha-xi-biao-ji-shu-jie-fa-y-a0mg/) | 简单 | 🤩🤩🤩 | | [705. 设计哈希集合](https://leetcode-cn.com/problems/design-hashset/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/design-hashset/solution/yi-ti-san-jie-jian-dan-shu-zu-lian-biao-nj3dg/) | 简单 | 🤩🤩🤩🤩 | | [706. 设计哈希映射](https://leetcode-cn.com/problems/design-hashmap/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/design-hashmap/solution/yi-ti-shuang-jie-jian-dan-shu-zu-lian-bi-yhiw/) | 简单 | 🤩🤩🤩🤩 | +| [726. 原子的数量](https://leetcode-cn.com/problems/number-of-atoms/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/number-of-atoms/solution/gong-shui-san-xie-shi-yong-xiao-ji-qiao-l5ak4/) | 困难 | 🤩🤩🤩🤩 | | [888. 公平的糖果棒交换](https://leetcode-cn.com/problems/fair-candy-swap/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/fair-candy-swap/solution/gong-shui-san-xie-yi-ti-shuang-jie-po-su-uant/) | 简单 | 🤩🤩 | | [1074. 元素和为目标值的子矩阵数量](https://leetcode-cn.com/problems/number-of-submatrices-that-sum-to-target/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/number-of-submatrices-that-sum-to-target/solution/gong-shui-san-xie-you-hua-mei-ju-de-ji-b-uttw/) | 困难 | 🤩🤩🤩 | | [1178. 猜字谜](https://leetcode-cn.com/problems/number-of-valid-words-for-each-puzzle/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/number-of-valid-words-for-each-puzzle/solution/xiang-jin-zhu-shi-xiang-jie-po-su-wei-yu-3cr2/) | 困难 | 🤩🤩🤩🤩 | diff --git "a/Index/\345\240\206.md" "b/Index/\345\240\206.md" index 43dd9f77..d17e12dc 100644 --- "a/Index/\345\240\206.md" +++ "b/Index/\345\240\206.md" @@ -6,4 +6,5 @@ | [480. 滑动窗口中位数](https://leetcode-cn.com/problems/sliding-window-median/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/sliding-window-median/solution/xiang-jie-po-su-jie-fa-you-xian-dui-lie-mo397/) | 困难 | 🤩🤩🤩🤩 | | [692. 前K个高频单词](https://leetcode-cn.com/problems/top-k-frequent-words/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/top-k-frequent-words/solution/gong-shui-san-xie-xiang-jie-shi-yong-ha-8dxt2/) | 中等 | 🤩🤩🤩🤩 | | [703. 数据流中的第 K 大元素](https://leetcode-cn.com/problems/kth-largest-element-in-a-stream/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/kth-largest-element-in-a-stream/solution/jian-da-ti-de-duo-chong-jie-fa-mou-pao-p-d1qi/) | 简单 | 🤩🤩🤩 | +| [726. 原子的数量](https://leetcode-cn.com/problems/number-of-atoms/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/number-of-atoms/solution/gong-shui-san-xie-shi-yong-xiao-ji-qiao-l5ak4/) | 困难 | 🤩🤩🤩🤩 | diff --git "a/Index/\346\240\210.md" "b/Index/\346\240\210.md" index 1db7a998..719c286b 100644 --- "a/Index/\346\240\210.md" +++ "b/Index/\346\240\210.md" @@ -5,6 +5,7 @@ | [155. 最小栈](https://leetcode-cn.com/problems/min-stack/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/min-stack/solution/tu-li-zhan-shi-shuang-zhan-shi-xian-zui-fcwj5/) | 简单 | 🤩🤩🤩🤩🤩 | | [232. 用栈实现队列](https://leetcode-cn.com/problems/implement-queue-using-stacks/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/implement-queue-using-stacks/solution/sha-shi-jun-tan-fu-za-du-ya-wo-de-suan-f-gb6d/) | 简单 | 🤩🤩🤩🤩🤩 | | [341. 扁平化嵌套列表迭代器](https://leetcode-cn.com/problems/flatten-nested-list-iterator/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/flatten-nested-list-iterator/solution/yi-ti-shuang-jie-dfsdui-lie-di-gui-zhan-kvwhy/) | 中等 | 🤩🤩🤩 | +| [726. 原子的数量](https://leetcode-cn.com/problems/number-of-atoms/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/number-of-atoms/solution/gong-shui-san-xie-shi-yong-xiao-ji-qiao-l5ak4/) | 困难 | 🤩🤩🤩🤩 | | [1190. 反转每对括号间的子串](https://leetcode-cn.com/problems/reverse-substrings-between-each-pair-of-parentheses/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/reverse-substrings-between-each-pair-of-parentheses/solution/gong-shui-san-xie-shi-yong-shuang-duan-d-r35q/) | 中等 | 🤩🤩🤩🤩🤩 | | [面试题 03.01. 三合一](https://leetcode-cn.com/problems/three-in-one-lcci/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/three-in-one-lcci/solution/yi-ti-shuang-jie-er-wei-shu-zu-yi-wei-sh-lih7/) | 简单 | 🤩🤩🤩 | diff --git "a/Index/\346\250\241\346\213\237.md" "b/Index/\346\250\241\346\213\237.md" index e38d85d6..eab1e67c 100644 --- "a/Index/\346\250\241\346\213\237.md" +++ "b/Index/\346\250\241\346\213\237.md" @@ -21,6 +21,7 @@ | [451. 根据字符出现频率排序](https://leetcode-cn.com/problems/sort-characters-by-frequency/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/sort-characters-by-frequency/solution/gong-shui-san-xie-shu-ju-jie-gou-yun-yon-gst9/) | 中等 | 🤩🤩🤩🤩 | | [566. 重塑矩阵](https://leetcode-cn.com/problems/reshape-the-matrix/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/reshape-the-matrix/solution/jian-dan-ti-zhong-quan-chu-ji-ke-yi-kan-79gv5/) | 简单 | 🤩🤩🤩 | | [645. 错误的集合](https://leetcode-cn.com/problems/set-mismatch/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/set-mismatch/solution/gong-shui-san-xie-yi-ti-san-jie-ji-shu-s-vnr9/) | 简单 | 🤩🤩🤩 | +| [726. 原子的数量](https://leetcode-cn.com/problems/number-of-atoms/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/number-of-atoms/solution/gong-shui-san-xie-shi-yong-xiao-ji-qiao-l5ak4/) | 困难 | 🤩🤩🤩🤩 | | [766. 托普利茨矩阵](https://leetcode-cn.com/problems/toeplitz-matrix/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/toeplitz-matrix/solution/cong-ci-pan-du-qu-cheng-ben-fen-xi-liang-f20w/) | 简单 | 🤩🤩🤩 | | [867. 转置矩阵](https://leetcode-cn.com/problems/transpose-matrix/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/transpose-matrix/solution/yi-you-wei-jin-huo-xu-ni-neng-kan-kan-zh-m53m/) | 简单 | 🤩🤩🤩🤩 | | [896. 单调数列](https://leetcode-cn.com/problems/monotonic-array/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/monotonic-array/solution/wei-shi-yao-yi-ci-bian-li-yao-bi-liang-c-uglp/) | 简单 | 🤩🤩🤩🤩 | diff --git "a/LeetCode/721-730/726. \345\216\237\345\255\220\347\232\204\346\225\260\351\207\217\357\274\210\345\233\260\351\232\276\357\274\211.md" "b/LeetCode/721-730/726. \345\216\237\345\255\220\347\232\204\346\225\260\351\207\217\357\274\210\345\233\260\351\232\276\357\274\211.md" new file mode 100644 index 00000000..b11fb373 --- /dev/null +++ "b/LeetCode/721-730/726. \345\216\237\345\255\220\347\232\204\346\225\260\351\207\217\357\274\210\345\233\260\351\232\276\357\274\211.md" @@ -0,0 +1,188 @@ +### 题目描述 + +这是 LeetCode 上的 **[726. 原子的数量](https://leetcode-cn.com/problems/number-of-atoms/solution/gong-shui-san-xie-shi-yong-xiao-ji-qiao-l5ak4/)** ,难度为 **困难**。 + +Tag : 「模拟」、「数据结构运用」、「栈」、「哈希表」、「优先队列」 + + + +给定一个化学式 `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` 只包含字母、数字和圆括号,并且题目中给定的是合法的化学式。 + +--- + +### 数据结构 + 模拟 + +一道综合模拟题。 + +相比于[(题解)227. 基本计算器 II](https://leetcode-cn.com/problems/basic-calculator-ii/solution/shi-yong-shuang-zhan-jie-jue-jiu-ji-biao-c65k/) 的表达式计算问题,本题设计模拟流程的难度要低很多,之所谓定位困难估计是使用到的数据结构较多一些。 + +为了方便,我们约定以下命名: +* 称一段完整的连续字母为「原子」 +* 称一段完整的连续数字为「数值」 +* 称 `(` 和`)` 为「符号」 + +基本实现思路如下: + +1. 在处理入参 `s` 的过程中,始终维护着一个哈希表 `map`,`map` 中 **实时维护** 着某个「原子」对应的实际「数值」(即存储格式为 `{H:2,S:1}`); + + > 由于相同原子可以出在 `s` 的不同位置中,为了某个「数值」对「原子」的累乘效果被重复应用,我们这里应用一个”小技巧“:为每个「原子」增加一个”编号后缀“。即实际存储时为 `{H_1:2, S_2:1, H_3:1}`。 + +2. 根据当前处理到的字符分情况讨论: + * 符号:直接入栈; + * 原子:继续往后取,直到取得完整的原子名称,将完整原子名称入栈,同时在 `map` 中计数加 $1$; + * 数值:继续往后取,直到取得完整的数值并解析,然后根据栈顶元素是否为 `)` 符号,决定该数值应用给哪些原子: + * 如果栈顶元素不为 `)`,说明该数值只能应用给栈顶的原子 + * 如果栈顶元素是 ),说明当前数值可以应用给「连续一段」的原子中 + +3. 对 `map` 的原子做 “合并” 操作:`{H_1:2, S_2:1, H_3:1}` => `{H:3, S:1}` ; + +4. 使用「优先队列(堆)」实现字典序排序(也可以直接使用 `List`,然后通过 `Collections.sort` 进行排序),并构造答案。 + +代码: +```Java [] +class Solution { + class Node { + String s; int v; + Node (String _s, int _v) { + s = _s; v = _v; + } + } + public String countOfAtoms(String s) { + int n = s.length(); + char[] cs = s.toCharArray(); + Map map = new HashMap<>(); + Deque d = new ArrayDeque<>(); + int idx = 0; + for (int i = 0; i < n; ) { + char c = cs[i]; + if (c == '(' || c == ')') { + d.addLast(String.valueOf(c)); + i++; + } else { + if (Character.isDigit(c)) { + // 获取完整的数字,并解析出对应的数值 + int j = i; + while (j < n && Character.isDigit(cs[j])) j++; + String numStr = s.substring(i, j); + i = j; + int cnt = Integer.parseInt(String.valueOf(numStr)); + + // 如果栈顶元素是 ),说明当前数值可以应用给「连续一段」的原子中 + if (!d.isEmpty() && d.peekLast().equals(")")) { + List tmp = new ArrayList<>(); + + d.pollLast(); // pop ) + while (!d.isEmpty() && !d.peekLast().equals("(")) { + String cur = d.pollLast(); + map.put(cur, map.getOrDefault(cur, 1) * cnt); + tmp.add(cur); + } + d.pollLast(); // pop ( + + for (int k = tmp.size() - 1; k >= 0; k--) { + d.addLast(tmp.get(k)); + } + + // 如果栈顶元素不是 ),说明当前数值只能应用给栈顶的原子 + } else { + String cur = d.pollLast(); + map.put(cur, map.getOrDefault(cur, 1) * cnt); + d.addLast(cur); + } + } else { + // 获取完整的原子名 + int j = i + 1; + while (j < n && Character.isLowerCase(cs[j])) j++; + String cur = s.substring(i, j) + "_" + String.valueOf(idx++); + map.put(cur, map.getOrDefault(cur, 0) + 1); + i = j; + d.addLast(cur); + } + } + } + + // 将不同编号的相同原子进行合并 + Map mm = new HashMap<>(); + for (String key : map.keySet()) { + String atom = key.split("_")[0]; + int cnt = map.get(key); + Node node = null; + if (mm.containsKey(atom)) { + node = mm.get(atom); + } else { + node = new Node(atom, 0); + } + node.v += cnt; + mm.put(atom, node); + } + + // 使用优先队列(堆)对 Node 进行字典序排序,并构造答案 + PriorityQueue q = new PriorityQueue((a,b)->a.s.compareTo(b.s)); + for (String atom : mm.keySet()) q.add(mm.get(atom)); + + StringBuilder sb = new StringBuilder(); + while (!q.isEmpty()) { + Node poll = q.poll(); + sb.append(poll.s); + if (poll.v > 1) sb.append(poll.v); + } + + return sb.toString(); + } +} +``` +* 时间复杂度:最坏情况下,每次处理数值都需要从栈中取出元素进行应用,处理 `s` 的复杂度为 $O(n^2)$;最坏情况下,每个原子独立分布,合并的复杂度为 $O(n)$;将合并后的内容存入优先队列并取出构造答案的复杂度为 $O(n\log{n})$;整体复杂度为 $O(n^2)$ +* 空间复杂度:$O(n)$ + +--- + +### 最后 + +这是我们「刷穿 LeetCode」系列文章的第 `No.726` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。 + +在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。 + +为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode 。 + +在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。 +