官网传送门
参考文献
题目描述
输入案例
官网给的都是图片,本人已手敲好,未免节约大家时间,故共享供复制粘贴。11
H2+O2=H2O
2H2+O2=2H2O
H2+Cl2=2NaCl
H2+Cl2=2HCl
CH4+2O2=CO2+2H2O
CaCl2+2AgNO3=Ca(NO3)2+2AgCl
3Ba(OH)2+2H3PO4=6H2O+Ba3(PO4)2
3Ba(OH)2+2H3PO4=Ba3(PO4)2+6H2O
4Zn+10HNO3=4Zn(NO3)2+NH4NO3+3H2O
4Au+8NaCN+2H2O+O2=4Na(Au(CN)2)+4NaOH
Cu+As=Cs+Au
解题思路
巴科斯范式,递归定义,所以肯定要用递归的思想解题。下面采用自顶向下的方法介绍解题思路。-
分别处理等号两边的
<expr>
,得到各自的原子类别及相应的数目
。若两边相同,返回true;否则,返回false; -
将
<expr>
拆分为多个<coef><formula>
,解析<coef>
。解析<formula>
,所得的<atom : nums>
中nums需乘以coef
-
解析
<formula>
注意:此时 s 只可能以大小字母或 ‘(’ 开头- ‘(’ 开头
a. 寻找与之匹配的’)’
b. 计算 ‘)’ 后面的系数coef
c. 递归 : 将括号里的内容和time * coef
传给analyzeFormula
- 大写字母开头
a. 判断 s 第二位是否是小写字母,得到原子名
b. 计算原子后面的系数 coef
c. 将原子和其数目time * coef
推进map
中
d. 递归 : 将系数后面的内容和time
传给analyzeFormula
- ‘(’ 开头
AC代码
import java.util.Map;
import java.util.Map.Entry;
import java.util.Scanner;
import java.util.HashMap;
import java.util.Set;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = in.nextInt();
in.nextLine();
while (n-- > 0) {
if (isEqualFormula(in.nextLine())) {
System.out.println("Y");
} else {
System.out.println("N");
}
}
in.close();
}
public static Boolean isEqualFormula(String s) {
// 获取等号两边表达式
String[] expression = s.split("=");
String left_expression = expression[0];
String right_expression = expression[1];
// 解析等号两边表达式,获得其原子组成及相应原子数目
Map<String, Integer> left_atom = analyzeExpression(left_expression);
Map<String, Integer> right_atom = analyzeExpression(right_expression);
// 判断方程式是否配平
if (left_atom.equals(right_atom)) {
return true;
} else {
return false;
}
}
// 解析表达式
public static Map<String, Integer> analyzeExpression(String s) {
// 存储整个表达式的原子组成
Map<String, Integer> map = new HashMap<>();
// 存储某个 <coef><formula> 的原子组成
Map<String, Integer> cur = new HashMap<>();
// 顺序处理每一个 <coef><formula>
String[] exprs =s.split("\\+");
for(String expr : exprs) {
int loc = 0; // 标记第一个非 0 元素的位置
while(loc < expr.length() && expr.charAt(loc) >= '0' && expr.charAt(loc) <= '9') loc++;
// loc 等于 0 说明 <coef> 为 1,否则解析
int coef = loc == 0 ? 1 : Integer.parseInt(expr.substring(0, loc));
// 对 <formula> 进行解析,将 coef 作为倍数传进去,返回map
cur = analyzeFormula(expr.substring(loc), coef);
// 依次将 cur 中的内容补充到 map 中
Set<Entry<String, Integer>> set = cur.entrySet();
for(Entry<String, Integer> item : set) {
String key = item.getKey();
int val = item.getValue();
if(map.containsKey(key)) {
map.put(key, map.get(key) + val);
}
else map.put(key, val);
}
}
return map;
}
public static Map<String, Integer> analyzeFormula(String s, int time) {
/*
注意:此时 s 只可能以大小字母或 '(' 开头
1. '(' 开头
a. 寻找与之匹配的')'
b. 计算 ')' 后面的系数 coef
c. 递归 : 将括号里的内容和 time * coef 传给 analyzeFormula
2. 大写字母开头
a. 判断 s 第二位是否是小写字母,得到原子名
b. 计算原子后面的系数 coef
c. 将原子和其数目 time * coef 推进 map 中
d. 递归 : 将系数后面的内容和 time 传给 analyzeFormula
*/
Map<String, Integer> map = new HashMap<>();
if(s.isEmpty()) return map;
// 以括号开头,去括号,计算系数,递归
if(s.charAt(0) == '(') {
int banlance = 1; // 左括号数 - 右括号数
int loc = 1; // 与该 '(' 对应的 ')' 的后一个位置
while(banlance > 0) {
if(s.charAt(loc) == '(') banlance++;
else if(s.charAt(loc) == ')') banlance--;
loc++;
}
// right 记录 ')' 的后一个位置,loc 继续寻找系数 coef 的后一个位置
int right = loc;
while(loc < s.length() && s.charAt(loc) >= '0' && s.charAt(loc) <= '9') {
loc++;
}
int coef = loc == right ? 1 : Integer.parseInt(s.substring(right, loc));
Map<String, Integer> cur = new HashMap<>();
Set<Entry<String, Integer>> set;
// 递归括号里面的东西
cur = analyzeFormula(s.substring(1, right - 1), time * coef);
set = cur.entrySet();
for(Entry<String, Integer> item : set) {
String key = item.getKey();
int val = item.getValue();
if(map.containsKey(key)) {
map.put(key, map.get(key) + val);
}
else map.put(key, val);
}
// 递归括号系数后面的东西
cur = analyzeFormula(s.substring(loc), time);
set = cur.entrySet();
for(Entry<String, Integer> item : set) {
String key = item.getKey();
int val = item.getValue();
if(map.containsKey(key)) {
map.put(key, map.get(key) + val);
}
else map.put(key, val);
}
}
// 此时只可能以大写字母开头
else {
String key;
int loc = 1; // 标记系数此时的地方
if(s.length() > 1 && s.charAt(1) >= 'a' && s.charAt(1) <= 'z') {
key = s.substring(0, 2);
loc = 2;
}
else key = s.substring(0, 1);
// right 记录原子的后一个位置也即系数起始的位置,loc 继续寻找系数 coef 的后一个位置
int right = loc;
while(loc < s.length() && s.charAt(loc) >= '0' && s.charAt(loc) <= '9') loc++;
int coef = loc == right ? 1 : Integer.parseInt(s.substring(right, loc));
if(map.containsKey(key)) {
map.put(key, map.get(key) + coef * time);
}
else map.put(key, coef * time);
Map<String, Integer> cur = new HashMap<>();
Set<Entry<String, Integer>> set;
// 递归该原子及其系数后面的东西
cur = analyzeFormula(s.substring(loc), time);
set = cur.entrySet();
for(Entry<String, Integer> item : set) {
key = item.getKey();
int val = item.getValue();
if(map.containsKey(key)) {
map.put(key, map.get(key) + val);
}
else map.put(key, val);
}
}
return map;
}
}
注意事项
太多需要注意的地方了,就不说了…