java - 以编程方式从给定化学式中分离原子

标签 java parsing data-processing

我正在尝试解决这个问题 - https://www.e-olymp.com/en/problems/7549但我无法通过所有测试(只通过了1/4)。我正在使用这些输入测试我的代码:

(AlC2)3Na4
3Al+6C+4Na

Gh(G2H3(H1A45)2)5(Bn6Mn3)5
450A+30Bn+10G+Gh+25H+15Mn

(Na1000)10Na02
10002Na

所以,看起来它有效,但它不起作用。任何提示都会很棒。

这是问题本身: 分子 M 的化学式描述了其原子组成。化学式遵循以下语法:

M := G | MG

G := S | SC

S := A | '('M')'

C := T | NE

E := D |德E

T := '2' | ... | '9'

N := '1' | ... | '9'

D := '0' | ..| '9'

A := U | UL | UL L

U := 'A' | ..| 'Z'

L := 'a' | ..| 'z'

计数 C 表示其之前的子组 S 的乘数。例如,H2O有2个H(氢)和1个O(氧)原子,(AlC2)3Na4含有3个Al(铝)、6个C(碳)和4个Na(钠)原子。

输入

包含多个测试用例。对于每个测试用例,都会有一行包含有效的化学式。每行不超过 100 个字符。

输出

对于每一行,都会有一行输出,它是化学物质的原子分解,以总和的形式显示,如示例输出所示。原子按字典顺序列出,并且隐含计数为 1,但未明确写入。输出中没有空格。正确输出中的所有计数都可以用 32 位有符号整数表示。

这是我的代码(它可能看起来很恶心,但无论如何):

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Scanner;
//Gh(G2H3(H1A45)2)5(Bn6Mn3)5

public class Main {

    static Scanner mIn;
    static PrintWriter mOut;

    public static void main(String[] args) {
        mIn = new Scanner(System.in);
        mOut = new PrintWriter(System.out);

        String line = mIn.nextLine();

        ArrayList<Atom> atoms = new ArrayList<>();

        ArrayList<Integer> startBr = new ArrayList<>();
        for (int i = 0; i < line.length(); i++) {
            if (line.charAt(i) == '(') {
                //starting
                startBr.add(atoms.size());
            } else if (line.charAt(i) == ')') {
                //ending
                int n = 1;

                if (line.length() > i + 1 && isNum(line.charAt(i + 1))) {
                    n = line.charAt(i + 1) - '0';
                    i++;
                    while (line.length() > i + 1 && isNum(line.charAt(i + 1))) {
                        n *= 10;
                        n += line.charAt(i + 1) - '0';
                        i++;
                    }
                }

                for (int j = startBr.get(startBr.size() - 1); j < atoms.size(); j++) {
                    atoms.get(j).n *= n;
                }

                startBr.remove(startBr.size() - 1);
            } else if (Character.isUpperCase(line.charAt(i))) {
                Atom atom = new Atom();
                atom.name = String.valueOf(line.charAt(i));
                if (line.length() > i + 1 && isCont(line.charAt(i + 1))) {
                    atom.name += String.valueOf(line.charAt(i + 1));
                    i++;

                    if (line.length() > i + 1 && isNum(line.charAt(i + 1))) {
                        atom.n = line.charAt(i + 1) - '0';
                        i++;

                        while (line.length() > i + 1 && isNum(line.charAt(i + 1))) {
                            atom.n *= 10;
                            atom.n += line.charAt(i + 1) - '0';
                            i++;
                        }
                    }
                }

                if (line.length() > i + 1 && isNum(line.charAt(i + 1))) {
                    atom.n = Integer.parseInt(String.valueOf(line.charAt(i + 1)));
                    i++;
                    while (line.length() > i + 1 && isNum(line.charAt(i + 1))) {
                        atom.n *= 10;
                        atom.n += line.charAt(i + 1) - '0';
                        i++;
                    }
                }
                atoms.add(atom);
            }
        }

        for (int i = 0; i < atoms.size(); i++) {
            for (int j = i + 1; j < atoms.size(); j++) {
                if (atoms.get(i).name.equals(atoms.get(j).name)) {
                    atoms.get(i).n += atoms.get(j).n;
                    atoms.get(j).n = -1;
                }
            }
        }

        for (int i = 0; i < atoms.size(); i++) {
            if (atoms.get(i).n < 1) {
                atoms.remove(i);
            }
        }

        Collections.sort(atoms, ALPHABETICAL_ORDER);

        for (int i = 0; i < atoms.size(); i++) {
            p(atoms.get(i).toString());
            if (i != atoms.size() - 1) {
                p("+");
            }
        }
    }

    private static Comparator<Atom> ALPHABETICAL_ORDER = new Comparator<Atom>() {
        public int compare(Atom atom1, Atom atom2) {
            return atom1.name.compareTo(atom2.name);
        }
    };

    private static boolean isCont(char c) {
        return c >= 'a' && c <= 'z';
    }

    private static boolean isNum(char c) {
        return c >= '0' && c <= '9';
    }

    private static void p(Object obj) {
        mOut.print(obj);
        mOut.flush();
    }

    private static class Atom {
        public String name;
        public int n = 1;

        public String toString() {
            if (n == 1) {
                return name;
            }
            return n + name;
        }
    }
}

最佳答案

您是否尝试过使用 Na123O1234 作为输入?两者似乎都是语法所允许的?

顺便说一句:有些方法可能会更短......

private static boolean isCont(char c) {
  return c >= 'a' && c <= 'z';
}

private static isNum(char c) {
  return c >= '0' && c <= '9';
}

要将单个数字字符 c 转换为相应的值,您可以使用 Character.getNumericalValue(c) ——或者只是 (c - '0 ')。 Character 类 javadoc 可能包含针对您的用例的更有趣的提示...

附注 我真的不明白为什么在有条件地添加 cont 字母后不使用相同的数字解析代码......

让我添加一个您可能会觉得有用的代码片段:

while (line.length() > i + 1 && isNum(line.charAt(i + 1))) {
  atom.n = 10 * atom.n + (line.charAt(++i) - '0');
}

关于java - 以编程方式从给定化学式中分离原子,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36812305/

相关文章:

python - 如果行不相等,如何通过公共(public)列合并两个 csv 文件?

java - 正则表达式从输入字符串中提取表达式

java - 在Java中,我的数组似乎只存储我最后添加的值

java - 如何将元组值解析为 Person 对象?

php - 用 PHP/Python 解析文本?如何?什么?

Node.js + Selenium 如何正确解析 html

html - 使用 XPath 提取 td 值

C++多UDP socket数据处理

java - Android 无法从内部存储共享图像

python - 迭代巨大的 XML 文件并获取值?