【leetcode】化学公式解析

45 阅读1分钟

题目来源

leetcode.cn/leetbook/re…

题目

给定一个用字符串展示的化学公式,计算每种元素的个数。 规则如下:

元素命名采用驼峰命名,例如 Mg () 代表内部的基团,代表阴离子团 [] 代表模内部链节通过化学键的连接,并聚合 例如:H2O => H2O1 Mg(OH)2 => H2Mg1O2

格式:

输入:化学公式的字符串表达式,例如:K4[ON(SO3)2]2

输出:元素名称及个数:K4N2O14S4,并且按照元素名称升序排列

输入:K4[ON(SO3)2]2

输出:K4N2O14S4

解析

如果碰到括号就进栈出栈,使用哈希表保存每一个元素以及组成元素的个数。

ON(SO3)2为例,首先解析到ON直接保存。然后碰到括号新建一个哈希表入栈。

image.png

接着碰到右括号,出栈,然后解析到是2,于是将出栈元素个数x2;

image.png

接着排序转成对应的输出格式即可;

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)
}