CCF:201912-3 化学方程式(JAVA版)

2020-03-06  本文已影响0人  巨鹿lx

解题思路

首先,用两个Map分别收集等号左右两边的元素,对比两个map的内容即可。那么问题就转化成了如何收集每一个化学式的信息。代码细节见注释

import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class 化学方程式 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        scanner.nextLine();
        while(n-->0) {
            Map<String,Integer> ans1 = new HashMap<String , Integer>(); 
            Map<String,Integer> ans2 = new HashMap<String , Integer>(); 
            String s = scanner.nextLine();
            String[] split = s.split("=");
            String[] ls = split[0].split("\\+");
            String[] rs = split[1].split("\\+");
            for(String a : ls) {//处理等式左边
                getOne(ans1,a);
            }
            for(String a: rs) {//处理等式右边
                getOne(ans2,a);
            }
            for(Map.Entry<String , Integer> e : ans1.entrySet()) {//对比等式左右两边
                int v = e.getValue();
                String k = e.getKey();
                int vv = ans2.containsKey(k)?ans2.get(k):-1;
                if(!ans2.containsKey(k)||v!=vv) {
                    break;
                }else {
                    ans2.remove(e.getKey());
                }
            }
            if(ans2.size()==0)System.out.println("Y");
            else System.out.println("N");
        }
    }
    private static void getOne(Map<String, Integer> map,String s) {//先处理化学式系数
        char[] a = s.toCharArray();
        int l = 0;
        int r = a.length - 1;
        int x = 0;// 系数
        while (a[l] <= '9' && a[l] >= '0')
            x = x * 10 + a[l++] - '0';
        getItem(a, l, r, map, x==0?1:x);//再处理化学式内容(注意是递归使用)
    }
    //记录一项
    private static void getItem(char[] a, int l, int r, Map<String, Integer> map, int x) {
        String e = "";
        int num = 0;
        while (l <= r && a[l] != ')') {
            if(a[l]>='a'&&a[l]<='z') {//小写字母
                e+=a[l++];
            }else if (a[l] >= 'A' && a[l] <= 'Z') {//遇到大写字母意味着上一个元素结束
                add(map, e, x, num);;
                e ="" + a[l++];num = 0;
            } else if (a[l] <= '9' && a[l] >= '0') {// 数字
                num = num * 10 + a[l++] - '0';
            } else {// 左括号
                add(map, e, x, num);
                e = "";num = 0;
                int b[] = getnx(a, ++l, r);//得到右边界,倍数,下次需要处理的位置
                getItem(a, l, b[0], map, x * b[1]);
                l = b[2];
            }
        }
        add(map, e, x, num);
    }
     /**
      * 找到匹配表达式的系数和右边界,
      * b0是表达式右边界(包含越界),b1是括号外数字(越界置1)
      * b2是下次要开始的位置
      */
    private static int[] getnx(char[] a, int l, int r) {
        int count = 1,x = 0,rl = 0;
        while (count != 0) {
            if (a[l] == '(')count++;
            if (a[l] == ')')count--;
            l++;
        }
        rl = l-2;
        while(l<=r&&a[l]<='9'&&a[l]>='0') x = x*10+a[l++]-'0';
        return new int[] { rl, x==0?1:x ,l};
    }

    // 记录一个元素
    private static void add(Map<String, Integer> map, String e, int x, int num) {
        if(e.equals("")) return;
        map.put(e, map.getOrDefault(e, 0) + (num == 0 ? 1 : num) * x);
    }
}

附样例

2
888C222O+H2+Cl2=2HCl+(O888)(C888)222
88888Ba(OH)2(A(B(C)22)33)11=44444Ba(OH)2(A(B(C)22)33)11
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
上一篇下一篇

猜你喜欢

热点阅读