Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

competitive programming and input

Tags:

java

io


I'm practicing for a competitive tournament that will be in my faculty in a few weeks, and thus I encountered a small problem.
The competition restricted the use of java.io.* (except IOException...)
I need to read (from stdin) input, each test case is separated with a blank line. end of test cases - when EOF is found.
I need to find a way to get data from IO, without using java.io
so far, I got this (which works) - it returns a string containing each test case, and null when I'm out of test cases.

public static String getInput() throws IOException {
    int curr=0;
    int prev=0;
    StringBuilder sb = new StringBuilder();
    while (true) {
        curr = System.in.read();
        if (curr == -1) { 
            return null; //end of data
        }
        if (curr == '\r') {
            curr = System.in.read();
        }
        if (curr == prev && curr == '\n') {
            return sb.toString(); //end of test case
        } //else:
        sb = sb.append((char)curr);
        prev = curr;
    }
}

performance (for the IO) is neglected, so I don't care I read only one byte every time.
Question: Is there a more elegant (shorter and faster to code) way to achieve the same thing?

like image 341
amit Avatar asked Dec 09 '22 09:12

amit


2 Answers

In fact, there are a few ways that you can process input in Java in competitive programming.

Approach 1: Using java.util.Scanner

This is the simplest way to read input, and it is also really straightforward to use. It can be slow if you have a huge amount of input. If your program keeps getting TLE (Time Limit Exceeded), but your program has the correct time complexity, try reading input with the second or third approach.

Initialization Scanner sc = new Scanner(System.in);

Reading an integer: int n = sc.nextInt(); Approach 2: Using java.io.BufferedReader

Use this one if there is a huge amount of input, and when the time limit of the problem is strict. It does require some more work, involving splitting the input by spaces, or using Integer.parseInt(str); to extract integers from the input.

You can find a speed comparison here https://www.cpe.ku.ac.th/~jim/java-io.html

Initialization: BufferedReader reader = new BufferedReader(System.in);

Reading an integer: int n = Integer.parseInt(reader.readLine());

Approach 3: Reading directly from FileDescriptor using custom reader

This approach is the fastest approach possible in Java. It does require a lot of work, including implementing the reader, as well as debugging should any problems arise. Use this approach if the time limit is strict and if you are allowed to bring code into the competition. This method is tested to be much faster than the second approach, but it would not usually provide you with an advantage since it is only about 2x the speed of the BufferedReader approach.

This is one implementation of such an approach written by my friend: https://github.com/jackyliao123/contest-programming/blob/master/Utils/FastScanner.java

The usage of the reader really depends on your implementation of the reader. It is suggested to maintain one copy of the reader that is somewhat guaranteed to work, because the last thing you want in a contest is having a non-functional reader and debugging the rest of your program, thinking there are some bugs there.

Hope this helps and best wishes on your competition!

like image 96
Jim Gao Avatar answered Dec 29 '22 03:12

Jim Gao


You could try the following and make it efficient by wrapping the System.in.

public static String readLine() throws IOException {
    StringBuilder sb = new StringBuilder();
    for (int ch; (ch = System.in.read()) > 0;)
        if (ch == '\r') continue;
        else if (ch == '\n') break;
        else sb.append(ch);
    return sb.toString();
}

EDIT: On Oracle JVM, System.in is a BufferedInputStream which wraps a FileInputStream which wraps a FileDescriptor. All these are in java.io.

like image 31
Peter Lawrey Avatar answered Dec 29 '22 02:12

Peter Lawrey