作者: 负雪明烛
id: fuxuemingzhu
个人博客: http://fuxuemingzhu.cn/


题目地址: https://leetcode.com/problems/number-of-atoms/description/

题目描述:

Given a chemical formula (given as a string), return the count of each atom.

An atomic element always starts with an uppercase character, then zero or more lowercase letters, representing the name.

1 or more digits representing the count of that element may follow if the count is greater than 1. If the count is 1, no digits will follow. For example, H2O and H2O2 are possible, but H1O2 is impossible.

Two formulas concatenated together produce another formula. For example, H2O2He3Mg4 is also a formula.

A formula placed in parentheses, and a count (optionally added) is also a formula. For example, (H2O2) and (H2O2)3 are formulas.

Given a formula, output the count of all elements as a string in the following form: the first name (in sorted order), followed by its count (if that count is more than 1), followed by the second name (in sorted order), followed by its count (if that count is more than 1), and so on.

Example 1:

Input:
formula = "H2O"
Output: "H2O"
Explanation:
The count of elements are {'H': 2, 'O': 1}.

Example 2:

Input:
formula = "Mg(OH)2"
Output: "H2MgO2"
Explanation:
The count of elements are {'H': 2, 'Mg': 1, 'O': 2}.

Example 3:

Input:
formula = "K4(ON(SO3)2)2"
Output: "K4N2O14S4"
Explanation:
The count of elements are {'K': 4, 'N': 2, 'O': 14, 'S': 4}.

Note:

  • All atom names consist of lowercase letters, except for the first character which is uppercase.
  • The length of formula will be in the range [1, 1000].
  • formula will only consist of letters, digits, and round parentheses, and is a valid formula as defined in the problem.

题目大意

给出了一个化学分式,计算里面的原子个数是多少,并且按照原子字母的递增有序输出。

解题方法

方法一:DFS

这个题第一眼就看到了括号,立马想到了括号匹配问题。括号匹配问题使用一个记数指针,遇到左括号加一,遇到右括号减一,如果该记数指针等于0了,说明找到了匹配的括号。在这个题中就相当于找到了一个分子团,该分子团后面会有个数字,代表这个分子团出现的次数。所以,做法就是如果不是分子团,那么统计元素的个数;如果是分子团,那么把这个分子团当做分子,计算里面元素的个数再乘以外边的分子团的个数。所以就是个DFS问题。

比较难办的就是寻找每个元素,需要根据大小写和数字等判断;寻找个数,需要把字符串转成10进制。最后把分子式内的元素个数×分子式的个数的时候,按照元素迭代的方式做,不要使用对分子式个数的for循环去累加。

最坏的时间复杂度是O(N!),最优时间复杂度是O(N),空间复杂度是O(N)。其中N是分子的长度。

class Solution(object):
def countOfAtoms(self, formula):
"""
:type formula: str
:rtype: str
"""
count = self.dfs(formula)
res = ""
for atom, num in sorted(count.items()):
if num == 1:
res += atom
else:
res += atom + str(num)
return res def dfs(self, formula):
count = collections.Counter()
if not formula: return count
i = 0
while i < len(formula):
if formula[i].isalpha(): # 首字母是英文字符
atom = formula[i]
atomNum = 0
# 找到这个元素所有字符
i += 1
while i < len(formula) and formula[i].isalpha() and formula[i].islower():
atom += formula[i]
i += 1
while i < len(formula) and formula[i].isdigit(): # 后面是否有数字
atomNum = 10 * atomNum + int(formula[i])
i += 1
count[atom] += 1 if atomNum == 0 else atomNum # 使用加号
elif formula[i] == "(": # 括号匹配
left = i # 左括号位置
parent = 1 # 统计括号个数
while i < len(formula) and parent != 0:
i += 1
if formula[i] == "(":
parent += 1
elif formula[i] == ")":
parent -= 1
right = i
atomNum = 0
i += 1
while i < len(formula) and formula[i].isdigit(): # 后面是否有数字
atomNum = 10 * atomNum + int(formula[i])
i += 1
innerCount = self.dfs(formula[left + 1 : right])
for c, n in innerCount.items():
count[c] += n * atomNum
count += self.dfs(formula[i + 1 :])
return count

方法二:栈

看到括号匹配,也会让人立马想到栈,其实DFS本身就是栈实现的,所以也完全可以用栈来解决。

方法是,左括号进栈,然后把字母依次进栈,当遇到右括号的时候,需要对栈进行退栈操作,这个时候要统计每个元素的次数,当退栈的时候遇到左括号,说明内部的分子团已经结束,那么把遇到的第一个左括号退栈,把内部的分子团的各个元素和其个数进栈。然后遍历就好了!这个方法的好处是,当最后遍历结束的时候,栈里面保存的只剩下了已经统计好了的各个元素和其个数的对应,每个元素只会出现一次,相当于已经做了元素的求和操作,最后只需要排序即可。

为了方便,我把分子式用括号包了起来,方便栈操作的判断。

这个题做了很久,主要是查一个bug,查了一个小时,感觉很诡异。其实仔细对比一下和上面DFS的解法,大同小异。区别是我用字母n保存了分子式的长度,然后下面退栈的for循环中又使用了n这个变量名称!!由于python不用声明变量,所以直接把外边的n覆盖掉了!!做法很简单,把内部for循环里的变量名改一下就好了!生气!!

最坏的时间复杂度是O(N!),最优时间复杂度是O(N),空间复杂度是O(N)。其中N是分子的长度。

代码如下:

class Solution(object):
def countOfAtoms(self, formula):
"""
:type formula: str
:rtype: str
"""
stack = list()
formula = "(" + formula + ")1"
i = 0
n = len(formula) while i < n:
if i >= n: continue
if formula[i] == "(":
stack.append("(")
i += 1
elif formula[i] == ")":
parentNum = 0
i += 1
while i < n and formula[i].isdigit():
parentNum = 10 * parentNum + int(formula[i])
i += 1
count = collections.Counter()
while stack[-1] != "(":
atom, atomNum = stack.pop()
count[atom] += atomNum * parentNum
if stack[-1] == "(":
stack.pop()
for c, t in count.items(): # 刚开始把变量t写成了n!!错了很多次
stack.append((c, t))
elif formula[i].isalpha():
atom = formula[i]
atomNum = 0
i += 1
while i < n and formula[i].isalpha() and formula[i].islower():
atom += formula[i]
i += 1
while i < n and formula[i].isdigit():
atomNum = 10 * atomNum + int(formula[i])
i += 1
atomNum = 1 if atomNum == 0 else atomNum
stack.append((atom, atomNum)) res = ""
for atoms in sorted(stack):
if atoms == "(":
continue
c, n = atoms
if n == 1:
res += c
else:
res += c + str(n)
return res

参考资料:

日期

2018 年 10 月 4 日 —— 一个很不容易察觉的小错误,需要总结一下坑了!

【LeetCode】726. Number of Atoms 解题报告(Python)的更多相关文章

  1. 【LeetCode】62. Unique Paths 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 题目地址:https://leetcode.com/problems/unique-pa ...

  2. 【LeetCode】376. Wiggle Subsequence 解题报告(Python)

    [LeetCode]376. Wiggle Subsequence 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.c ...

  3. 【LeetCode】911. Online Election 解题报告(Python)

    [LeetCode]911. Online Election 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ ...

  4. 【LeetCode】870. Advantage Shuffle 解题报告(Python)

    [LeetCode]870. Advantage Shuffle 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn ...

  5. 【LeetCode】435. Non-overlapping Intervals 解题报告(Python)

    [LeetCode]435. Non-overlapping Intervals 解题报告(Python) 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemi ...

  6. 【LeetCode】498. Diagonal Traverse 解题报告(Python)

    [LeetCode]498. Diagonal Traverse 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id: fuxuemingzhu 个人博客: htt ...

  7. 【LeetCode】481. Magical String 解题报告(Python)

    [LeetCode]481. Magical String 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http:/ ...

  8. 【LeetCode】397. Integer Replacement 解题报告(Python)

    [LeetCode]397. Integer Replacement 解题报告(Python) 标签: LeetCode 题目地址:https://leetcode.com/problems/inte ...

  9. 【LeetCode】91. Decode Ways 解题报告(Python)

    [LeetCode]91. Decode Ways 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fux ...

随机推荐

  1. python15正则表达式

    ------------恢复内容开始------------ python实现实现实现实现 import re #将表达式编译,返回一个对象, pattern = re.compile(r" ...

  2. 【讲座】詹显全——Proteoforms在肿瘤中应用

    Proteoforms/Protein species这个概念还是比较有意义的. 人类结构基因组测序接近尾声,人们就从结构基因组学研究转向功能基因组学研究,即对转录组和蛋白质组进行研究.1995年正式 ...

  3. CQC认证与3C认证的区别是什么

    中国CCC认证为中国的强制性认证(什么产品能做,CQC网上都要目录), CQC是自愿性的,(不能做CCC认证的产品,可以选择做CQC认证) 产品想要在中国市场上流通,特别是进入超市,商场,招标工厂等的 ...

  4. 关于写SpringBoot+Mybatisplus+Shiro项目的经验分享二:问题1

    框架: SpringBoot+Mybatisplus+Shiro 简单介绍:关于写SpringBoot+Mybatisplus+Shiro项目的经验分享一:简单介绍 添加时,如果失败,不能正确跳转 c ...

  5. 20. VIM命令操作技巧

    V可视化选中当前行,根据光标可多行 ctrl+v 可视化块 v可视化根据光标 行间移动 快速增删改查 d 0 删除当前位置到行首 d $ 删除当前位置到行尾 d  t  (" ] ) )符号 ...

  6. 零基础学习java------day6----数组

    0. 内容概览 补充:main方法中的数组 1. 数组的概述 概念: 用来存储一组相同数据类型的集合(或者叫容器) 注意事项: 1. 数组中的元素类型必须一致 2. 数组本身是引用数据类型,但是里面的 ...

  7. stlink 无法再keil中识别 按下复位键可以识别

    最近遇到一个很是头痛的问题 本来板子是好好的,就是从公司带回的家里 然后再次用stlink烧写程序的时候就出现了问题: 但是查看电脑端,上面是有stlink的 也就是电脑是好的, 我立刻又试了一下家中 ...

  8. 【swift】用Xib实现自定义警告框(Alert)(安卓叫法:Dialog对话框)

    在写这篇博客前,先感谢两篇博客 [如何自定义的思路]:https://www.cnblogs.com/apprendre-10-28/p/10507794.html [如何绑定Xib并且使用]:htt ...

  9. oracle中的数组

    Oracle中的数组分为固定数组和可变数组. 一.固定数组固定数组:在定义的时候预定义了数组的大小,在初始化数组时如果超出这个大小,会提示ORA-06532:超出小标超出限制!语法:        T ...

  10. 11-如何通过newman生成不同类型的测试报告

    postman生成测试报告需要一个插件:newman ,并且这个插件需要先安装 . 安装步骤: 安装nodejs: newman是由nodejs开发,所以要先安装它的运行环境,下载地址:http:// ...