JAVA CCF-201912-3 化学表达式

欢迎访问我的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;
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值