以编程方式将给定化学式的原子分开

时间:2016-04-23 14:52:02

标签: 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 | M G

G:= S | S C

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

C:= T | N E

E:= D | D E

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

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

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

A:= U |你L |你好

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

L:='a'| .. | 'Z'

计数C表示其前面的子组S的乘数。例如,H2O有两个H(氢)和一个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;
        }
    }
}

1 个答案:

答案 0 :(得分:1)

您是否尝试过O1234private 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') - 或仅使用while (line.length() > i + 1 && isNum(line.charAt(i + 1))) { atom.n = 10 * atom.n + (line.charAt(++i) - '0'); } 。 Character类javadoc可能包含更多有趣的用例提示......

<强> P.S。 我真的不明白为什么在有条件地添加 cont 字母后你不使用相同数字的解析代码....

让我抛出你可能会觉得有用的代码片段:

var map;

function initMap() {
  map = new google.maps.Map(document.getElementById('map'), {
    center: {
      lat: 37.4419,
      lng: -122.1419
    },
    zoom: 8
  });
  var line = new google.maps.Polyline({
    path: [new google.maps.LatLng(37.4419, -122.1419), new google.maps.LatLng(37.4519, -122.1519)],
    strokeColor: "#FF0000",
    strokeOpacity: 1.0,
    strokeWeight: 10,
    geodesic: true,
    map: map
  });
  // extend line from each end along its existing heading
  // pick 20e6 meters as an arbitrary length
  var lineHeading = google.maps.geometry.spherical.computeHeading(line.getPath().getAt(0), line.getPath().getAt(1));
  var newPt0 = google.maps.geometry.spherical.computeOffset(line.getPath().getAt(0), 20000000, lineHeading);
  line.getPath().insertAt(0, newPt0);
  var newPt1 = google.maps.geometry.spherical.computeOffset(line.getPath().getAt(1), 20000000, lineHeading + 180);
  line.getPath().push(newPt1);
}

google.maps.event.addDomListener(window, "load", initMap);