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?
In fact, there are a few ways that you can process input in Java in competitive programming.
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);
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());
FileDescriptor
using custom readerThis 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!
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With