Reputation: 278
I'm trying to solve this - https://www.e-olymp.com/en/problems/7549 but I can't pass all tests (passed only 1/4). I was testing my code with these inputs:
(AlC2)3Na4
3Al+6C+4Na
Gh(G2H3(H1A45)2)5(Bn6Mn3)5
450A+30Bn+10G+Gh+25H+15Mn
(Na1000)10Na02
10002Na
So, looks like it works but it does not work. Any hint would be great.
Here is problem itself: The chemical formula of a molecule M describes its atomic make-up. Chemical formulas obey the following grammar:
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 | U L | U L L
U := 'A' | .. | 'Z'
L := 'a' | .. | 'z'
The count C represents a multiplier for the subgroup S that precedes it. For example, H2O has two H (hydrogen) and one O (oxygen) atoms, and (AlC2)3Na4 contains 3 Al (aluminum), 6 C (carbon) and 4 Na (sodium) atoms.
Input
Contains multiple test cases. For each test case, there will be one line, containing a valid chemical formula. Each line will have no more than 100 characters.
Output
For each line there will be one line of output which is the atomic decomposition of the chemical in the form of a sum as shown in the sample output. The atoms are listed in lexicographical order, and a count of 1 is implied and not explicitly written. There are no blank spaces in the output. All of the counts in the correct output will be representable in 32-bit signed integers.
And this is my code (it might looks disgusting but anyway):
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;
}
}
}
Upvotes: 0
Views: 524
Reputation: 18813
Have you tried Na123
or O1234
as input? Both seem to be permitted by the grammar?
BTW: Some of the methods could be much shorter...
private static boolean isCont(char c) {
return c >= 'a' && c <= 'z';
}
private static isNum(char c) {
return c >= '0' && c <= '9';
}
For converting a single digit character c
to the corresponding value, you could use Character.getNumericalValue(c)
-- or just (c - '0')
. The Character class javadoc probably contains more interesting hints for your use case...
P.S. I don't really understand why you don't use the same number parsing code after conditionally adding the cont letter....
Let me throw in a code fragment you might find useful:
while (line.length() > i + 1 && isNum(line.charAt(i + 1))) {
atom.n = 10 * atom.n + (line.charAt(++i) - '0');
}
Upvotes: 1