欢迎访问我的CCF认证解题目录
题目描述
思路过程
使用HashMap<String, Integer>
来检查每条等式是否相等,左边的表达式对应的原子数量为正,右边为负,当结果集里面所有的key
都为0
时,表示该等式相等
新建一个类Node
,来存储每个括号区间内的原子数量,有两个指针,分别指向父亲和儿子.
将读入的字符串按=
进行切割,在按+
进行切割,对于每个化学式:
- 首先读入系数,如果没有系数的话则表示1
- 如果下一个字符是
(
,则继续读系数,然后新建一个Node
,进入子区间 - 如果下一个字符是
)
,则判断后面是否有数字,如果有数字则要将该区间的所有原子数量乘以该数字,再将该区间的所有原子数量乘以化学式的系数,接着回退到父区间,将子区间的原子都搬运到父区间中 - 如果下一个字符是原子,则判断后面是否有数字,如果有数字,存储的时候要乘以该数字
每次读取数字时,都要将index
移动都相应的位置。
最后再将所有原子搬运到结果集中
测试数据:
14
H2+O2=H2O
2H2+O2=2H2O
H2+Cl2=2NaCl
H2+Cl2=2HCl
C1H4+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
3H(2O)=3HO2
3(2O(H)2)2=3(O(H)2)2
2((H)(H))=H4
1(2(3(A1)))=(((1A)1)2)3
结果:NYNYYYYYYYYNYY
代码
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int n = Integer.parseInt(in.nextLine());//化学表达式的数量
while ( n-- != 0 ) {
String[] line = in.nextLine().split("=");
HashMap<String, Integer> result = new HashMap<>();//初始化
int val = -1;
for ( String str: line ) {//切割了等于号,左右两边
String[] second = str.split("\\+");
val = val*-1;//等号左右两边不同
for ( String temp: second ) {//切割了加号,每一个化学式
Node node = new Node();
Stack<Integer> preNum = new Stack<>();//存储相应括号内的系数,对应后进先出
preNum.add(getPreNum(temp));
for ( int i = preNum.peek() == -1?0:Integer.toString(preNum.peek()).length(); i < temp.length(); i++ ) {
if ( temp.charAt(i) == '(' ) {//递归处理
preNum.add(i+1 < temp.length()?getPreNum(temp.substring(i+1)):1);//读取系数
if ( preNum.peek() != -1 ) i += Integer.toString(preNum.peek()).length();//移动对应的i
Node child = new Node();
node.child = child;
child.parent = node;
node = child;
} else if ( temp.charAt(i) == ')' ) {//递归出来
int lastNum = i+1 < temp.length()?getPreNum(temp.substring(i+1)):1;//获取系数
if ( lastNum != -1 ) {//移动对应的i,且如果后面有系数的话要乘起来
i += Integer.toString(lastNum).length();
mulid(node.map, lastNum);
}
node = node.parent;
mulid(node.child.map, preNum.pop());//乘以化学式的系数
res(node.map, node.child.map);//搬运到父区间
} else {//读取原子
StringBuffer sb = new StringBuffer(temp.charAt(i)+"");
while ( i+1 < temp.length() && Character.isLowerCase(temp.charAt(i+1)) ) {
sb.append(temp.charAt(++i));
}
int lastNum = i+1 < temp.length()?getPreNum(temp.substring(i+1)):1;//获取系数
if ( lastNum != -1 ) i += Integer.toString(lastNum).length();//移动到对应位置
if ( !node.map.containsKey(sb.toString()) ) node.map.put(sb.toString(), 0);
node.map.put(sb.toString(), node.map.get(sb.toString())+Math.abs(lastNum)*val);//绝对值用来特判-1,刚好为1
}
}
mulid(node.map, preNum.pop());//乘以表达式的系数
res(result, node.map);//搬运到结果集
}
}
boolean flag = true;
for ( String key: result.keySet() ) {
if ( result.get(key) != 0 ) {
flag = false;
break;
}
}
if ( flag ) System.out.println("Y");
else System.out.println("N");
}
}
//从初始位置读取数字,如果没有的话返回-1.
public static int getPreNum( String str ) {
if ( str.length() > 0 && Character.isDigit(str.charAt(0)) ) {
int i = 0;
for ( ; i < str.length() && Character.isDigit(str.charAt(i)); i++ );
return Integer.parseInt(str.substring(0, i));
} else return -1;
}
//将子区间搬到父区间
public static void res( Map<String, Integer> node, Map<String, Integer> data ) {
for ( String key: data.keySet() ) {
if ( !node.containsKey(key) ) node.put(key, 0);
node.put(key, node.get(key) + data.get(key));
}
}
//乘以系数
public static void mulid( Map<String, Integer> node, int lastNum ) {
lastNum = Math.abs(lastNum);
for ( String key: node.keySet() ) {
node.put(key, node.get(key)*lastNum);
}
}
}
class Node {
HashMap<String, Integer> map = new HashMap<>();//存储该区间的原子
Node child = null, parent = null;
}