题目链接 为了降低难度。以下分别为,只考虑大小写字母和等号的方程组、加入数字、加入括号(非嵌套)


import re


def cnt(string: str):
    pattern = r"[A-Z][a-z]*" #匹配元素
    elements = re.findall(pattern, string)
    count = {}
    # 统计元素词频
    for item in elements:
        if item in count:
            count[item] += 1
        else:
            count[item] = 1
    return count


if __name__ == '__main__':
    n = int(input())
    for i in range(n):
        equation = input()
        left, right = equation.split("=")
        # 统计等式左边的元素个数
        leftCnt = cnt(left)
        # 统计等式右边的元素个数
        rightCnt = cnt(right)
        # 输入比较结果
        if leftCnt == rightCnt:
            print("Y")
        else:
            print("N")

note: 这道题继续使用正则进行处理,不考虑括号情况可以轻松刷到60分

【更新60分简洁代码版本】

import re


# 统计形如2CaCl2、CuCl2等单个项的元素个数
def cnt_word(word: str):  # word = 2CaCl2
    pattern = r"(\d*)(\w+)"
    # 返回的结果对象中obj,使用obj[groupId](1或2,注意是1开始,不是0)访问系数或系数后面的内容
    # 例如对于2CaCl2,将返回 "2","CaCl2"
    groups = re.match(pattern, word)  # d

    # 1、提取系数和非系数内容, 后面会使用系数将元素数量翻倍
    coefficient = groups[1]
    if coefficient == "":
        coefficient = 1
    else:
        coefficient = int(coefficient)
    # 2、提取非系数内容
    none_coe = groups[2]
    # 2.1 提取所有的元素项目,例如 Ca 、Cl2
    pattern = r"([A-Z][a-z]*)(\d*)"  # 比如CaNo3H3,将返回[('Ca', ''), ('No', '3'), ('H', '3')]
    ele_list = re.findall(pattern, none_coe)
    t_cnt = {}
    for item in ele_list:
        # 取得对于的元素和下标
        element = item[0]
        ele_cnt = int(item[1]) if item[1] != "" else 1
        # 存入字典
        if element in t_cnt:
            t_cnt[element] += ele_cnt
        else:
            t_cnt[element] = ele_cnt

    # 3.将系数并入结果
    for key in t_cnt:
        t_cnt[key] *= coefficient
    return t_cnt


# 返回等式某一边的元素统计
def cnt_one_side(one_side: str):
    side_cnt = {}
    for word in one_side.split("+"):
        t_cnt = cnt_word(word)
        for ele in t_cnt:
            if ele in side_cnt:
                side_cnt[ele] += t_cnt[ele]
            else:
                side_cnt[ele] = t_cnt[ele]
    return side_cnt


if __name__ == '__main__':
    n = int(input())
    for i in range(n):
        equation = input()
        left, right = equation.split("=")
        # 统计等式两边的元素个数
        left_cnt = cnt_one_side(left)
        right_cnt = cnt_one_side(right)
        # 输出结果
        if left_cnt == right_cnt:
            print("Y")
        else:
            print("N")
import re

# 分离系数和非系数部分,例如,对于输入4AuCl2(ON)2  ---> 4 和 AuCl2(ON)2
def sep_coe(item):
    pattern = r"(\d*)"
    # 返回的结果对象中obj,使用obj[groupId](1或2,注意是1开始,不是0)访问系数或系数后面的内容
    # 例如对于2CaCl2,将返回 "2","CaCl2"
    groups = re.match(pattern, item)  # d

    # 1、提取系数和非系数内容, 后面会使用系数将元素数量翻倍
    coefficient = groups[1]
    if coefficient == "":
        coefficient = 1
    else:
        coefficient = int(coefficient)
    # 2、提取非系数内容
    pattern = r"\d*(.+)"
    groups = re.findall(pattern, item)
    none_coe = groups[0]
    # 返回系数和非系数部分
    return coefficient, none_coe


# 统计简单项的元素个数例如。 H2 Cl2 PO3 等等不含有系数和括号的项
def cnt_simple_ele(ele: str):
    pattern = r"([A-Z][a-z]*)(\d*)"  # 比如CaNo3H3,将返回[('Ca', ''), ('No', '3'), ('H', '3')]
    ele_list = re.findall(pattern, ele)
    t_cnt = {}
    for item in ele_list:
        # 取得对于的元素和下标
        element = item[0]
        ele_cnt = int(item[1]) if item[1] != "" else 1
        # 存入字典
        if element in t_cnt:
            t_cnt[element] += ele_cnt
        else:
            t_cnt[element] = ele_cnt
    return t_cnt


# 统计含有括号的项的元素个数。例如Au(CN)3(OH)2中的(CN)3和(OH)2
def cnt_parentheses_ele(par_ele: str):
    p = r"\((\w+)\)(\d*)"
    res_list = re.findall(p, par_ele)
    # 经过正则表达式后:会被分割成两部分:括号里的内容和括号右边的数字
    cnt = {}
    for item in res_list:
        t_cnt = {}
        # 提取括号里内容和括号外数字
        simple_ele = item[0]
        subscript = int(item[1]) if item[1] != "" else 1
        # 统计括号内元素的数量,再乘以括号外的数字
        cnt_simple = cnt_simple_ele(simple_ele)

        for ele in cnt_simple:
            cnt_simple[ele] *= subscript
        for ele in cnt_simple:

            if cnt.get(ele) is not None:
                cnt[ele] += cnt_simple[ele]
            else:
                cnt[ele] = cnt_simple[ele]
    return cnt


# 统计由 "+" 分割的项目元素个数.例如 4AuCl2(ON)2
def cnt_word(word: str):  # word = 2CaCl2
    cnt = {}
    # 1.获取系数和非系数部分
    coefficient, none_coe = sep_coe(word)
    # 对系数后的内容分两种情况提取。
    # 2.1 提取所有的元素项目(不带括号)的元素个数统计,例如 Ca 、Cl2
    patt = r"\((\w+)\)(\d*)"
    simple_str = re.sub(patt, "", none_coe)
    cnt_simple = cnt_simple_ele(simple_str)
    # 2.2 提取带括号的,输入(ON)2 -----> ON , 3
    cnt_parentheses = cnt_parentheses_ele(none_coe)

    # 3.合并2.1和2.2的结果
    for ele in cnt_simple:
        if ele in cnt:
            cnt[ele] += cnt_simple[ele] * coefficient
        else:
            cnt[ele] = cnt_simple[ele] * coefficient
    for ele in cnt_parentheses:
        if ele in cnt:
            cnt[ele] += cnt_parentheses[ele] * coefficient
        else:
            cnt[ele] = cnt_parentheses[ele] * coefficient
    return cnt


# 返回等式某一边的元素统计
def cnt_one_side(one_side: str):
    side_cnt = {}
    for word in one_side.split("+"):
        t_cnt = cnt_word(word)
        for ele in t_cnt:
            if ele in side_cnt:
                side_cnt[ele] += t_cnt[ele]
            else:
                side_cnt[ele] = t_cnt[ele]
    return side_cnt


if __name__ == '__main__':
    n = int(input())
    for i in range(n):
        equation = input()
        left, right = equation.split("=")
        # 统计等式两边的元素个数
        left_cnt = cnt_one_side(left)
        right_cnt = cnt_one_side(right)
        # 输出结果
        if left_cnt == right_cnt:
            print("Y")
        else:
            print("N")

体会:
虽然只拿了80分。没有考虑嵌套。但是我相信聪明的你们,利用我封装好的函数,对程序修改以下便能获得满分。
二八原则:随着考虑情况的越来越多。代码从最开始的30行–>60行–>120行。翻倍增长。后面的20%可以要占用你80%的时间和精力。
本文充分利用的正则表达式进行分割。提取数字和元素。当然自己实现不会太难。但代码会更长

【更新:某大佬的写法】:

# coding=utf-8
# Copyright (c) 2020. ItsukiFujii.

import re
import collections

list_formula = []
list_terms_left = []
list_terms_right = []
list_res = []
dict_atoms_left = collections.defaultdict(int)
dict_atoms_right = collections.defaultdict(int)


# calculate each single compound
def fk_it(formula):
    stack = list()
    stack.append(collections.Counter())
    found = re.findall(r'([A-Z][a-z]?)(\d*)|(\()|(\))(\d*)', formula)
    for name, n_atom, open_paren, close_paren, coef in found:
        if name:
            stack[-1][name] += int(n_atom or 1)
        if open_paren:
            stack.append(collections.Counter())
        if close_paren:
            top = stack.pop()
            for key in top.keys():
                top[key] *= int(coef or 1)
            stack[-1] += top #合并两个Counter
    return dict(stack.pop())


# handle each single equation
def handle_equation(terms_all, dict_atoms):
    for term in terms_all:
        coef_term = re.match(r'\d+', term)
        coef_term = 1 if coef_term is None else int(coef_term.group())
        tmp = fk_it(term)
        for key in tmp.keys():
            tmp[key] *= coef_term
        for k, v in tmp.items():
            if str(dict_atoms.keys()).find(k) != -1:
                dict_atoms[k] += v
            else:
                dict_atoms.update({k: v})


if __name__ == '__main__':
    num_of_formula = int(input())
    for i in range(num_of_formula):
        list_formula.append(input())
        list_res.append('Y')

    # split the equations
    for item in list_formula:
        list_terms_left.append(item[:item.find('=')].split('+'))
        list_terms_right.append(item[item.find('=') + 1:].split('+'))

    # judge whether the number of atom on both side is equal
    cntr_tmp = 0
    for terms_all_left, terms_all_right in zip(list_terms_left, list_terms_right):
        dict_atoms_left.clear()
        dict_atoms_right.clear()

        # left part
        handle_equation(terms_all_left, dict_atoms_left)
        # right part
        handle_equation(terms_all_right, dict_atoms_right)
        # compare the numbers
        if dict_atoms_left != dict_atoms_right:
            list_res[cntr_tmp] = 'N'

        # print(dict_atoms_left, dict_atoms_right, list_res[cntr_tmp])  # for debug
        print(list_res[cntr_tmp])
        cntr_tmp += 1

【更新】100分最新代码!经过多月积淀,有所突破!!自己写的代码精简度和速度再次提高(50行左右,不计算空行情况下)
import re
from collections import Counter


def getInput():
    cnt = int(input())
    equ = []
    for _ in range(cnt):
        equ.append(input())
    return cnt, equ


# 统计 4Na(Au(CN)2)2 等等元素个数
def cntSingleEle(ele):
    coef_term = re.match(r'\d+', ele)
    coef_term = 1 if coef_term is None else int(coef_term.group())
    stack = []
    stack.append(Counter())
    pattern = r'([A-Z][a-z]?)(\d*)|(\()|(\))(\d*)'
    for e, suffix, parL, parR, parSuffix in re.findall(pattern, ele):
        if parL:  # 进栈
            stack.append(Counter())
        elif parR:  # 出栈
            t = stack.pop()
            for key in t.keys():
                t[key] *= (int(parSuffix) if parSuffix else 1)
            stack[-1] += t
        else:
            stack[-1][e] += (int(suffix) if suffix else 1)
    for key in stack[0].keys():
        stack[0][key] *= coef_term

    return dict(stack.pop())


# 返回元素统计 :H2 + O2 --> {'H':2,'O': 2}
def cntOneSide(expr):
    counter = Counter()
    for ele in expr.split('+'):
        counter += cntSingleEle(ele)
    return counter


def isBalanced(equation):  # H2+02 = H2O2
    left, right = equation.split('=')
    if cntOneSide(left) == cntOneSide(right):
        return True
    else:
        return False


if __name__ == '__main__':
    n, equations = getInput()
    for equation in equations:
        if isBalanced(equation):
            print('Y')
        else:
            print('N')