UVa online judge #458 time limit exceeded - java

I am trying to solve UVa problem 458 - decoder and I came up with the following algorithm which gives me the correct output for the sample input data, but runs longer than allowed.
public class Decoder {
public void decoder() {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()) {
String line = sc.nextLine();
for (int i = 0; i < line.length(); i++) {
if(line.charAt(i)>=32 && line.charAt(i)<=126)
System.out.print((char) (line.charAt(i) - 7));
}
System.out.println();
}
}
}
What I've looked into
Well I have read the forums and most of the solutions were pretty similar, I have been researching if there was a way of avoiding the for loop which is running through the string and printing out the new char. But this loop is inevitable, this algorithm's time complexity is always going to be n^2.
The problem also mentions to only change ASCII printable values, which is why I set the condition to check if its greater than or equal to 32 and 126. According to Wikipedia that is the range of printable values.
http://ideone.com/XkByW9

Avoid decoding the stream to characters. It's ok to use bytes if you only have to support ASCII.
Read and write the data in big chunks to avoid function/system call overhead.
Avoid unnecessary allocations. Currently you are allocating new String for every line.
Do not split the input into lines to avoid bad performance for very small lines.
Example:
public static void main(String[] args) throws IOException {
byte[] buffer = new byte[2048];
while (true) {
int len = System.in.read(buffer);
if (len <= 0) {
break;
}
for (int i = 0; i < len; i++) {
...
}
System.out.write(buffer, 0, len);
}
}
It will process the input as you would normally process a binary file. For every iteration, it will read up to 2048 bytes into a buffer, process them and write them to standard output. Program will end when EOF is reached and read returns -1. 2048 is usually a good buffer size, but you might want to try different sizes and see which one works best.

Never use Scanner for long inputs. The scanner is unbelievably slower than other means of reading input in Java, such as BufferedReader. This UVa problem looks like one with a quite long input.

Related

Using 2 BufferedReaders to read 1 file

So i'm trying to create a 2d character array from a .txt file. The first while-loop calculates to number of columns and rows. The second while-loop is to enter chars into the 2d array. However when i create BufferedReader br2 and use readLine() and then try to print it the line prints out "null". Why does the second BufferedReader start at the end of the file?
public Maze(FileReader reader){
try {
BufferedReader br = new BufferedReader(reader);
cols = 0;
rows = 0;
str = br.readLine();
while (str != null) {
if (str.length() > cols) {
cols = str.length();
}
rows++;
str = br.readLine();
}
}
catch (IOException e) {
System.out.println("Error");
}
maze = new char[getNumRows()][getNumColumns()];
try {
BufferedReader br2 = new BufferedReader(reader);
line = br2.readLine();
System.out.println(line);
while ((line = br2.readLine()) != null) {
System.out.println(line);
for (int i = 0; i < getNumColumns(); i++) {
maze[row][i] = line.charAt(i);
}
row++;
}
}
catch (IOException e) {
System.out.println("Error");
}
}
this is how I call it from main
public class RobotTest {
public static void main(String[] args) throws IOException{
File file = new File(args[0]);
Maze maze = new Maze(new FileReader(file));
}
}
You are using the same reader for initializing both of the BufferedReaders and after the first one finishes reading that means the next one will continue reading at the EOF. You must return the second one to the beginning of the file before iterating again through it.
You can reset the pointer of the reader by using FileReader.reset()
You can checkout mark() as well in the documentation.
Source: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/io/Reader.html#reset()
As the name indicates, a 'BufferedReader' uses a buffer.
There's a reason for that.
Harddisks, network communications, SSDs - these are all concepts that tend to operate in terms of packets. They write or read largish chunks. For example, with networking, you can't just 'send a bunch of bytes down a wire' - you need to send a packet, because the packet includes information about where the packet is supposed to go and to solve the ordering issue (when you send packets on the internet, one you sent later may arrive earlier, so packets need an index number on them so the receiver can re-order them in the right way).
If you send one byte, okay - but that'll be ~200 bytes on the wire. Hence, sending 1 byte 5000 times is ~1 million bytes sent, whereas sending 5000 bytes in one go is only 5200 bytes; a 1000x difference!
Similar principles apply elsewhere, thus, 'send 1 byte' or 'read 1 byte' is often incredibly, factor 1000x inefficient.
Hence, buffers. You ASK for one character or one line (which can be quite a short line) from your BufferedReader and it will dutifully give you this, but under the hood it has read an entire largish chunk (because that is efficient), and will be fielding your further requests for e.g. another line from this buffer until it runs out and then it grabs another chunk.
The upshot of all that, is that you CAN NEVER use a reader ever again once you wrap it in a bufferedreader. You are 'committed' to the buffer now: That BufferedReader is the only thing you can read, from here on out, until the stream is done.
You're creating another one, and thus, your code is buggy: You're now effectively skpping whatever the first BufferedReader buffered; given that you're getting null out, that means right now it buffered the entire contents of the file, but perhaps on another system, a bigger file, it wouldn't return null, but some line deep into the file. Either way, you cannot use that filereader anymore once you have created a bufferedreader.
The solution is simple enough: Make the bufferedreader, once, and pass that around. Don't keep making BufferedReader instances out of it.
Also, resources need to be 'protected' - you must close them no matter how your code exits. If your code throws an error you need to still close the resources; failure to do so means your program will eventually get stuck and will be incapable of opening files, forever - the only way out is to completely close the app. Finally, FileReader is basically broken; it uses 'platform default charset encoding' which is anyone's guess. You want to 'hardcode' what encoding it has, and usually, the right answer is "UTF-8". This doesn't matter if the only characters are simple ASCII, but it's 2021. People use emojis, snowmen, and almost every language on the planet needs more than just a to z. If your encoding settings are off, it'll be mangled gobbledygook.
The newer Files API (java.io.File is outdated and you probably don't want to use it anymore) defaults to UTF-8, which is great, saves us some typing.
thus:
public static void main(String[] args) throws IOException {
try (var reader = Files.newBufferedReader(Paths.get(args[0]))) {
Maze maze = new Maze(reader);
}
}

SpotBugs - Method ignores results of InputStream.read()

I am having some problems debugging a code, I managed to debug all bugs but one:
Method ignores results of InputStream.read(), the debugger (SpotBugs) says the problem is on reader.read(buffer, 0, n) and advises me to check the return value otherwise the caller will not be able to correctly handle the case where fewer bytes were read than the caller requested.
char[] buffer = new char[n];
try{
reader = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
reader.read(buffer,0,n);
reader.close();
}
catch(RuntimeException e) {
throw e;
}
catch(Exception e) {
System.out.println("Something went wrong");
}
for(int i=0;i<buffer.length;i++) {
int swap = i % 2;
if (Integer.toString(swap).equals(Integer.toString(1))) {
buffer[i] = ' ';
}
}
System.out.print(buffer);
How can I fix this bug?
read() when used with a buffer returns the actual number of the bytes read (or -1 for end of stream). It's possible that the buffer isn't filled completely with a single read (although small buffers are, since data is transferred in blocks), so you need to make sure (i.e. use a while loop) you've read the amount of bytes you intended to.
R. Castro gave you good explanation, but what's missing (in obvious words) is you are not checking how many bytes are being read from file. The number can be different than size of your buffer. That's what spotbug is trying to tell you. Your file can be longer or shorter than buffer size. You are not handling the case where file is longer than buffer size. And loop you have needs to be changed to whatever number of bytes are read than buffer.length

Why does java.util.Scanner exist? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Scanner vs. BufferedReader
Is there any situation in which it's apropriate to use java.util.Scanner in order to read input of some sort? In my small test I've found it to be incredibly slow compared to java.util.Bufferedreader or implementing your own reader from java.util.InputStreamReader.
So is there any reason as to why I would want to use a Scanner?
From the docs:
A simple text scanner which can parse primitive types and strings
using regular expressions.
That won´t do a BufferedReader.
The Scanner class main purpose is for parsing text for primitive types and strings using regular expressions. You can provide several resource types to read from.
While Scanner is relatively slower, it is often more than fast enough and it is much more powerful than BufferedReader.
public static void main(String... args) throws IOException {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < 10000; i++)
sb.append("line: ").append(i).append("\n");
String lines = sb.toString();
for (int i = 0; i < 6; i++) {
testBufferedReader(lines);
testScanner(lines);
}
}
private static void testBufferedReader(String text) throws IOException {
int count = 0;
BufferedReader br = new BufferedReader(new StringReader(text));
long start = System.nanoTime();
while (br.readLine() != null)
count++;
long time = System.nanoTime() - start;
System.out.printf("BufferedReader.readLine() took an average of %,d ns count=%,d%n", time / count, count);
}
private static void testScanner(String text) throws IOException {
int count = 0;
Scanner sc = new Scanner(new StringReader(text));
long start = System.nanoTime();
while (sc.hasNextLine()) {
sc.nextLine();
count++;
}
long time = System.nanoTime() - start;
System.out.printf("Scanner nextLine took an average of %,d ns count=%,d%n", time / count, count);
}
finally prints
BufferedReader.readLine() took an average of 124 ns count=10,000
Scanner nextLine took an average of 1,549 ns count=10,000
While the relative difference is large, the scanner is less than a couple of micro-seconds each.
Scanner- Many of its methods is the idea of parsing the input stream into tokens. BufferedReader doesn't rely on breaking up its input into tokens. It allows you to read character by character if you want. It can read an entire line and let you do what you want.
A scanner into it; it can do all that a BufferedReader can do and at the same level of efficiency as well. However, in addition a Scanner can parse the underlying stream for primitive types and strings using regular expressions. It can also tokenize the underlying stream with the delimiter of your choice. It can also do forward scanning of the underlying stream disregarding the delimiter!
EDIT Just Forget to mention...
"A scanner however is not thread safe, it has to be externally synchronized."
Here is the difference between java.lang.util.scanner and java.lang.util buffered reader. While both are useful in taking input from the user in a java class, there is a significant difference that one needs to understand.
Scanner is a single token input system that uses white spaces as the default delimiter. Although you can change this to other formats using various other methods.
While buffered reader is a buffered input system. It takes chunks (stream) of data and then feeds into the data type that the user wants to store it in. So until you flush or the buffer is full, the reader stream wont give you data..

Skip x last lines when reading a text file

I read text data from big file line by line.
But I need to read just n-x lines(don't read last x lines) .
How can I do it without reading whole file more than 1 time?
(I read line and immediately process it, so i can't go back)
In this post I'll provide you with two completely different approaches to solving your problem, and depending on your use case one of the solutions will fit better than the other.
Alternative #1
This method is memory efficient though quite complex, if you are going to skip a lot of contents this method is recommended since you only will store one line at a time in memory during processing.
The implementation of it in this post might not be super optimized, but the theory behind it stands clear.
You will start by reading the file backwards, searching for N number of line breaks. When you've successfully located where in the file you'd like to stop your processing later on you will jump back to the beginning of the file.
Alternative #2
This method is easy to comprehend and is very straight forward. During execution you will have N number of lines stored in memory, where N is the number of lines you'd like to skip in the end.
The lines will be stored in a FIFO container (First In, First Out). You'll append the last read line to your FIFO and then remove and process the first entry. This way you will always process lines at least N entries away from the end of your file.
Alternative #1
This might sound odd but it's definitely doable and the way I'd recommend you to do it; start by reading the file backwards.
Seek to the end of the file
Read (and discard) bytes (towards the beginning of the file) until you've found SKIP_N line breaks
Save this position
Seek to the beginning of the file
Read (and process) lines until you've come down to the position you've stored away
Example code:
The code below will strip off the last 42 lines from /tmp/sample_file and print the rest using the method described earlier in this post.
import java.io.RandomAccessFile;
import java.io.File;
import java.lang.Math;
public class Example {
protected static final int SKIP_N = 42;
public static void main (String[] args)
throws Exception
{
File fileHandle = new File ("/tmp/sample_file");
RandomAccessFile rafHandle = new RandomAccessFile (fileHandle, "r");
String s1 = new String ();
long currentOffset = 0;
long endOffset = findEndOffset (SKIP_N, rafHandle);
rafHandle.seek (0);
while ((s1 = rafHandle.readLine ()) != null) {
; currentOffset += s1.length () + 1; // (s1 + "\n").length
if (currentOffset >= endOffset)
break;
System.out.println (s1);
}
}
protected static long findEndOffset (int skipNLines, RandomAccessFile rafHandle)
throws Exception
{
long currentOffset = rafHandle.length ();
long endOffset = 0;
int foundLines = 0;
byte [] buffer = new byte[
1024 > rafHandle.length () ? (int) rafHandle.length () : 1024
];
while (foundLines < skipNLines && currentOffset != 0) {
currentOffset = Math.max (currentOffset - buffer.length, 0);
rafHandle.seek (currentOffset);
rafHandle.readFully (buffer);
for (int i = buffer.length - 1; i > -1; --i) {
if (buffer[i] == '\n') {
++foundLines;
if (foundLines == skipNLines)
endOffset = currentOffset + i - 1; // we want the end to be BEFORE the newline
}
}
}
return endOffset;
}
}
Alternative #2
Read from your file line by line
On every successfully read line, insert the line at the back of your LinkedList<String>
If your LinkedList<String> contains more lines than you'd like to skip, remove the first entry and process it
Repeat until there are no more lines to be read
Example code
import java.io.InputStreamReader;
import java.io.FileInputStream;
import java.io.DataInputStream;
import java.io.BufferedReader;
import java.util.LinkedList;
public class Example {
protected static final int SKIP_N = 42;
public static void main (String[] args)
throws Exception
{
String line;
LinkedList<String> lli = new LinkedList<String> ();
FileInputStream fis = new FileInputStream ("/tmp/sample_file");
DataInputStream dis = new DataInputStream (fis);
InputStreamReader isr = new InputStreamReader (dis);
BufferedReader bre = new BufferedReader (isr);
while ((line = bre.readLine ()) != null) {
lli.addLast (line);
if (lli.size () > SKIP_N) {
System.out.println (lli.removeFirst ());
}
}
dis.close ();
}
}
You need to use a simple read-ahead logic.
Read x lines first and put them in a buffer. Then you can repeatedly read one line at a time, add it to the end of the buffer, and process the first line in the buffer. When you reach EOF, you have x unprocessed lines in the buffer.
Update: I noticed the comments on the question and my own answer, so just to clarify: my suggestion works when n is unknown. x should be known, of course. All you need to do is create a simple buffer, and then fill up the buffer with x lines, and then start your processing.
Regarding the implementation of the buffer, as long as we are talking about Java's built-in collections, a simple LinkedList is all you need. Since you'll be pulling one line out of the buffer for every line that you place in it, ArrayList won't perform well do to constant shifting of array indices. Generally speaking, an array-backed buffer would have to be circular to avoid bad performance.
Just read x lines ahead. That is have a queue of x lines.

competitive programming and input

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.
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!
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.
You can try using the java.util.Scanner class if java.util is allowed. It has useful methods for reading in a line, a token or even a number as needed. But it is slower than BufferedReader and possibly slower than using System.in.read() directly.
Since System.in implements the InputStream interface, it might also be some speedup to use System.in.read(byte[] b) to read in the input. This way you can read in a bunch of bytes at a time instead of just the one, which should be faster. But the added complexity of having to code and debug it during the contest might not be worth it.
Edit:
Searching the web I found someone discussing using System.in.read(byte[] b) in the UVa forum back when UVa had terrible Java support.
You can use a scanner
import java.util.Scanner;//put this above the class
Scanner scanner = new Scanner(System.in); //this creates the scanner
int input = scanner.nextInt();
.nextInt() takes integers
.nextLine() takes strings

Categories