Для скорости, следующий код:
- Использует
StringBuilder
для быстрой конкатенации в результирующий String
и быстрый вывод, поскольку в конце печатается только один массив String
, сохраняяненужные сбросы буфера. - Не создает группу
String
с при разборе ввода, только небольшие byte[]
и Integer
с в ArrayList
. - Вручнуюдля чтения использует буфер размером 64 КБ.
- Не воссоединяет токены с
"|"
в середине, чтобы потом снова разделить их. - Использует
HashMap<Integer, HashMap<Integer, Integer>>
вместо HashMap<Integer, ArrayList<Integer>>
чтобы сэкономить время при поиске элементов в списке (алгоритм переключается с времени O (n 2 ) на время O (n)).
Некоторые ускорения могут работать не так, как выwant:
- Не тратит время на правильную обработку Unicode.
- Не тратит время на правильную обработку отрицательных или переполненных чисел.
- Не важно, чтоСимволы-разделители (вы могли бы ввести
"1,2,3,4,5,6"
вместо этого, и он все равно работал бы так же, как "1|2\n3|4\n5|6\n"
).
Yoвы можете увидеть, что он дает правильные результаты для вашего тестового ввода здесь (за исключением того, что он разделяет выходные данные новыми строками, как в вашем коде).
private static final int BUFFER_SIZE = 65536;
private static enum InputState { START, MIDDLE }
public static void main(final String[] args) throws IOException {
// Input the numbers
final byte[] inputBuffer = new byte[BUFFER_SIZE];
final List<Integer> inputs = new ArrayList<>();
int inputValue = 0;
InputState inputState = InputState.START;
while (true) {
int j = 0;
final int bytesRead = System.in.read(inputBuffer, 0, BUFFER_SIZE);
if (bytesRead == -1) {
if (inputState == InputState.MIDDLE) {
inputs.add(inputValue);
}
break;
}
for (int i = 0; i < bytesRead; i++) {
byte ch = inputBuffer[i];
int leftToken = 0;
if (ch < 48 || ch > 57) {
if (inputState == InputState.MIDDLE) {
inputs.add(inputValue);
inputState = InputState.START;
}
}
else {
if (inputState == InputState.START) {
inputValue = ch - 48;
inputState = InputState.MIDDLE;
}
else {
inputValue = 10*inputValue + ch - 48;
}
}
}
}
System.in.close();
// Put the numbers into a map
final Map<Integer, Map<Integer, Integer>> map = new HashMap<>();
for (int i = 0; i < inputs.size();) {
final Integer left = inputs.get(i++);
final Integer right = inputs.get(i++);
final Map<Integer, Integer> rights;
if (map.containsKey(left)) {
rights = map.get(left);
}
else {
rights = new HashMap<>();
map.put(left, rights);
}
rights.putIfAbsent(right, rights.size() + 1);
}
// Prepare StringBuilder with results
final StringBuilder results = new StringBuilder();
for (int i = 0; i < inputs.size();) {
final Integer left = inputs.get(i++);
final Integer right = inputs.get(i++);
final Map<Integer, Integer> rights = map.get(left);
results.append(left).append('|').append(right);
results.append('[').append(rights.get(right)).append(',');
results.append(rights.size()).append(']').append('\n');
}
System.out.print(results);
}
Вы также можете использовать вручную64 КБ byte[]
выходной буфер также с System.out.write(outputBuffer, 0, bytesToWrite); System.out.flush();
, если вы хотите сэкономить память, хотя это намного больше работы.
Кроме того, если вы знаете минимальные и максимальные значения, которые вы увидите, выможно использовать массивы int[]
или int[][]
вместо Map<Integer, Integer>
или Map<Integer, Map<Integer, Integer>>
, хотя это также несколько сложнее.Хотя это было бы очень быстро.