【LeetCode】726、原子的数量

【LeetCode】726、原子的数量

文章目录

  • [一、递归: 嵌套类问题](#一、递归: 嵌套类问题)
    • [1.1 递归: 嵌套类问题](#1.1 递归: 嵌套类问题)
  • 二、多语言解法


一、递归: 嵌套类问题

1.1 递归: 嵌套类问题

遇到 ( 括号, 则递归计算子问题

遇到大写字母, 或遇到 ( 括号, 则清算历史, 并开始新的记录

记录由两部分组成: 大写字母开头的 或 子函数递归的结果

go 复制代码
// go
func countOfAtoms(s string) string {
    where := 0 // 全局变量, 记录 括号内递归 的终止位置, 用于继续从此计算

    var f func(i int) map[string]int // 输入 s 的下标, 输出 哈希表, 计算括号内的 原子统计
    f = func(i int) map[string]int {
        m := map[string]int{}
        name := "" // 字母历史, 如 Mg4 的 Mg
        pre := map[string]int{} // 哈希表历史, 如 (SO3)2 的 SO3
        cnt := 0 // 次数, 如 Mg4 的 4, 如 (SO3)2 的 2
        for i < len(s) && s[i] != ')' {
            c := s[i]
            if (c >= 'A' && c <= 'Z') || c == '(' { // 需要清算历史记录, 并开始新的记录
                // 清算历史记录
                fill(m, name, pre, cnt)
                name = ""
                clear(pre)
                cnt = 0

                // 开始新的记录
                if c >= 'A' && c <= 'Z' { // 大写字母
                    name += string(c) // 通过字母得到记录
                    i++
                } else { // 左括号 (
                    pre = f(i+1) // 通过递归得到记录
                    i = where + 1 // 从递归结束的位置, 继续遍历
                }
            } else if c >= 'a' && c <= 'z' {
                name += string(c)
                i++
            } else { // 数字 c >= '0' && c <= '9'
                cnt = cnt * 10 + int(c - '0')
                i++
            }
        }
        fill(m, name, pre, cnt) // 最后一次, 比如 H2Mg3, 当遍历到整个字符串结尾时 需要触发 把 最后的 Mg3 放入结果
        where = i // 标记此递归的结束位置, 后续顶层函数继续从 where + 1 处遍历, 否则肯定死循环
        return m
    }
    m := f(0)
    return format(m)
}

// name 重复 cnt 次, 或 pre 重复 cnt 次, 添加到 m 中
func fill(m map[string]int, name string, pre map[string]int, cnt int) {
    if cnt == 0 {cnt = 1} // 如 HMF 则 遍历到 M 时, 需清算 H, 但此时 cnt 为 0, 其实是因为省略了 H1 为 H, 所以需要当 cnt == 0 时把 cnt 置为 1
    if len(name) > 0 { // 是 name 的历史
        m[name]+=cnt
    } else { // 是 pre 的历史
        for atom, count := range pre {
            m[atom]+=count*cnt
        }
    }
}

func format(m map[string]int) (ans string) {
    sli := slices.Collect(maps.Keys(m)) // 无需哈希表, 收集 keys
    slices.Sort(sli) // 排序 keys, 从而得到有序哈希表
    for _, atom := range sli {
        cnt := m[atom]
        ans += atom
        if cnt > 1 {
            ans += strconv.Itoa(cnt)
        }
    }
    return
}

参考左神: 嵌套类问题 递归思路

二、多语言解法

C p p / G o / P y t h o n / R u s t / J s / T s Cpp/Go/Python/Rust/Js/Ts Cpp/Go/Python/Rust/Js/Ts

cpp 复制代码
// cpp
go 复制代码
// go 同上
python 复制代码
# python
rust 复制代码
// rust
js 复制代码
// js
ts 复制代码
// ts
相关推荐
溟洵3 小时前
【 C/C++ 算法】入门动态规划-----一维动态规划基础(以练代学式)
c语言·c++·算法
过河卒_zh15667663 小时前
9.12AI简报丨腾讯投资AI游戏平台,B站开源AniSora V3
人工智能·算法·游戏·aigc·算法备案·生成合成类算法备案
boonya3 小时前
Java垃圾回收机制理论算法及使用
jvm·算法·gc·垃圾收集器·理论
愚润求学3 小时前
【贪心算法】day9
c++·算法·leetcode·贪心算法
lingran__4 小时前
速通ACM省铜第二天 赋源码(Adjacent XOR和Arboris Contractio)
c++·算法
半桔5 小时前
【STL源码剖析】二叉世界的平衡:从BST 到 AVL-tree 和 RB-tree 的插入逻辑
java·数据结构·c++·算法·set·map
塔中妖6 小时前
【华为OD】分割数组的最大差值
数据结构·算法·华为od
weixin_307779136 小时前
最小曲面问题的欧拉-拉格朗日方程 / 曲面极值问题的变分法推导
算法
RTC老炮6 小时前
webrtc弱网-AlrDetector类源码分析与算法原理
服务器·网络·算法·php·webrtc
孤廖6 小时前
【算法磨剑:用 C++ 思考的艺术・Dijkstra 实战】弱化版 vs 标准版模板,洛谷 P3371/P4779 双题精讲
java·开发语言·c++·程序人生·算法·贪心算法·启发式算法