题目来源
题目
给定一个用字符串展示的化学公式,计算每种元素的个数。 规则如下:
元素命名采用驼峰命名,例如 Mg () 代表内部的基团,代表阴离子团 [] 代表模内部链节通过化学键的连接,并聚合 例如:H2O => H2O1 Mg(OH)2 => H2Mg1O2
格式:
输入:化学公式的字符串表达式,例如:K4[ON(SO3)2]2
输出:元素名称及个数:K4N2O14S4,并且按照元素名称升序排列
输入:K4[ON(SO3)2]2
输出:K4N2O14S4
解析
如果碰到括号就进栈出栈,使用哈希表保存每一个元素以及组成元素的个数。
以ON(SO3)2为例,首先解析到ON直接保存。然后碰到括号新建一个哈希表入栈。
接着碰到右括号,出栈,然后解析到是2,于是将出栈元素个数x2;
接着排序转成对应的输出格式即可;
package main
import (
"fmt"
"sort"
"strconv"
"unicode"
)
func countOfAtoms(formula string) string {
i, n := 0, len(formula)
//解析字母
parseA := func() string {
start := i
i++
for i < n && unicode.IsLower(rune(formula[i])) {
i++
}
return formula[start:i]
}
parsenum := func() (ans int) {
if i == n || !unicode.IsDigit(rune(formula[i])) {
return 1 //如果到了结束或者不是数字了,默认是1
}
for i < n && unicode.IsDigit(rune(formula[i])) {
//是数字
ans = ans*10 + int(formula[i]-'0')
i++
}
return
}
//栈进行保存,外围栈是总的个数,二层栈是需要操作的
stack := []map[string]int{{}}
for i < n {
//如果是(
if formula[i] == '(' || formula[i] == '[' {
i++
//新建一个栈
stack = append(stack, map[string]int{})
} else if formula[i] == ')' || formula[i] == ']' {
//表演出战.
i++
num := parsenum()
//出战.
atom := stack[len(stack)-1]
stack = stack[:len(stack)-1]
//遍历这个atom.然后往外层里加.
for k, v := range atom {
stack[len(stack)-1][k] = stack[len(stack)-1][k] + v*num
}
} else {
//如果是普通的,解析一下存储.
atom := parseA()
num := parsenum()
//保存.
stack[len(stack)-1][atom] = stack[len(stack)-1][atom] + num
}
}
//将栈中的元素保存成pair,然后进行排序》
type pair struct {
key string
num int
}
pairs := make([]pair, 0, len(stack[0]))
for k, v := range stack[0] {
pairs = append(pairs, pair{k, v})
}
sort.Slice(pairs, func(i, j int) bool {
return pairs[i].key < pairs[j].key
})
//排序好了之后,就按照顺序来.(拼接)如果是1,就算了
ans := []byte{}
for _, p := range pairs {
//这里猜是将Mg,转成M, g这种字符。
ans = append(ans, p.key...)
if p.num >= 1 {
ans = append(ans, strconv.Itoa(p.num)...)
}
}
return string(ans)
}
func main() {
var s string
fmt.Scan(&s)
a := countOfAtoms(s)
fmt.Print(a)
}