一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情。
说明:文章部分内容及图片出自网络,如有侵权请与我本人联系(主页有公众号:小攻城狮学前端)
作者:小只前端攻城狮、 主页:小只前端攻城狮的主页、 来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
【LeetCode 726. 原子的数量 】- JavaScript(双指针+滑动窗口)
题意描述
给你一个字符串化学式 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}。
思路分析:
这个题目可以说是括号匹配升级版的题目,同样需要用栈来解决。这道题实际上是一个比较复杂的字符统计操作。
递归
核心思想:就是嗯模拟,对于括号的情况,括号中的化学式每个原子都要乘以括号外的数值,所以可以取子串(这里用到了括号匹配,由于只需要找与之对应的括号,使用一个变量模拟栈即可),子串也是一个化学式,递归处理即可。
注意点:
-
同一个原子需要用小写字母这个信息来判断,容易忽视
-
parseNum默认返回1,而不是0
-
数量1不用append
-
string比较写成-,需要CompareTo
const countOfAtoms = function (formula) {
const len = formula.length
const isNumber = (c) => c > 47 && c < 58
const isUpperChar = (c) => c > 64 && c < 91
const isLowerChar = (c) => c > 96 && c < 123
let i = 0
const counter = () => {
let element = ''
let count = 0
let map = {}
const counterMap = () => {
const _count = count || 1
if (!element) return
if (typeof element === 'string') map[element] = (map[element] || 0) + _count
else {
Object.keys(element).forEach((ele) => {
map[ele] = (map[ele] || 0) + element[ele] * _count
})
}
}
while (i < len) {
const c = formula[i]
const cCode = c.charCodeAt()
i++
if (c === '(') {
counterMap()
element = counter()
count = 0
continue
}
if (c === ')') {
counterMap()
return map
}
if (isLowerChar(cCode)) element += c
else if (isUpperChar(cCode)) {
counterMap()
element = c
count = 0
} else if (isNumber(cCode)) {
const n = parseInt(c)
count = count * 10 + n
}
}
if (element || count) counterMap()
return map
}
const map = counter()
return Object.keys(map)
.sort()
.map((ele) => (ele += map[ele] === 1 ? '' : map[ele]))
.join('')
}
正则
思想:其实不能发现化学表达式都有很明显的字符串特征。首先使用正则表达式解析原子和数字。 正则表达式 /([A-Z][a-z]?)(\d*)/g
注意:正则表达式带有全局修饰符时,循环调用exec方法,方法内部会记录每次执行的索引,结果和match全局的正则表达式类似。合理利用可以方便很多。
var countOfAtoms = function(formula) {
const map = {}
let str = formula
while(str.includes('(')) {
str = str.replace(/\(([A-Z][a-z]*[0-9]*)+\)\d*/g, item => {
const atomStr = item.match(/[A-Za-z0-9]+/)[0]
const num = item.match(/\d$/) ? item.match(/\d*$/)[0] : 1
return atomStr.replace(/[A-Z][a-z]*[0-9]*/g, atom => {
return atom.match(/\d/) ? atom.replace(/\d+/, inNum => +inNum * +num) : atom + num
})
})
}
str.match(/[A-Z][a-z]*[0-9]*/g).forEach(item => {
let key = item.match(/[A-Z][a-z]*/)[0]
let value = item.match(/\d+$/)
value = value ? value[0] : 1
map[key] = map[key] ? (+map[key] + +value) : +value
})
return Object.entries(map).map(([key, value]) => {
return value === 1 ? key : key+value
}).sort().join('')
};
感谢阅读,希望能对你有所帮助,文章若有错误或者侵权,可以在评论区留言或在我的主页添加公众号联系我。
写作不易,如果觉得不错,可以「点赞」+「评论」 谢谢支持❤