Today when I submitted a solution to codeforces, I used int[] array and my submission got TLE(Time limit exceeded) & after changing it to Integer[] array surprisingly it got AC. I didn't get how the performance is improved.
import java.io.*;
import java.lang.reflect.Array;
import java.util.*;
public class Main {
static class Task {
public void solve(InputReader in, PrintWriter out) throws Exception {
int n = in.nextInt();
Integer[] a = new Integer[n];
for (int i = 0; i < n; i++) a[i] = in.nextInt();
Arrays.sort(a);
long count = 0;
for (int i = 0; i < n; i++) count += Math.abs(i + 1 - a[i]);
out.println(count);
}
}
public static void main(String[] args) throws Exception{
InputStream inputStream = System.in;
OutputStream outputStream = System.out;
InputReader in = new InputReader(inputStream);
PrintWriter out = new PrintWriter(outputStream);
Task task = new Task();
task.solve(in, out);
out.close();
}
static class InputReader {
public BufferedReader reader;
public StringTokenizer tokenizer;
public InputReader(InputStream stream) {
reader = new BufferedReader(new InputStreamReader(stream), 32768);
tokenizer = null;
}
public String next() {
while (tokenizer == null || !tokenizer.hasMoreTokens()) {
try {
tokenizer = new StringTokenizer(reader.readLine());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return tokenizer.nextToken();
}
public int nextInt() {
return Integer.parseInt(next());
}
}
}
The reason for it is quite simple: the time complexity of the solution with Integer is better.
Sounds strange, doesn't it?
Arrays.sort uses a dual pivot quick sort for primitives, which works in O(N^2) time in the worst case. The test case your solution fails is a specially constructed anti-quick sort test.
However, the version for objects uses merge sort, which runs in O(N * log N) time for any possible input.
Note that it's not a part of the Java language specification (it doesn't say how the sort method should be implemented), but it works like this in most of the real implementations (for example, it is the case for openjdk-8)
P.S. Things like this happen more or less frequently in competitive programming, so I'll recommend to either sort arrays of objects or to use collections.
Related
the question says: Create a class named HW09. In this class implement a method named primeCounter
with the following signature, that takes a file name as string (for example “numbers.txt”) and returns the number of prime numbers in the text file. Assume the text file only contains integer numbers.
I tried to build the code for the program But I keep getting these error messages and I'm not sure how to fix them and get the program running again. My knowledge of the file access concept is very weak and my professor is horrible. I hope someone can help me understand what went wrong
import java.io.*;
import java.util.Scanner;
class HW09 {
public static int primeCounter(String fileName) throws IOException {
int count= 0;
int number;
String x= null;
File filename= new File("C:/Users/black/Desktop/file.txt");
Scanner s = new Scanner(filename);
BufferedReader data= null;
data= new BufferedReader (new FileReader(filename));
while (s.hasNextInt()) {
number= Integer.parseInt(x);
int see=0;
for (int i =1; i<=number; i++) {
if (number%i==0) {
see = see+1;
}
if (see>2) {
break;
}
}
if (see==2) {
count = count+1;
}
}
return count;
}
public static void main (String args []) {
try {
String file= ("C:/Users/black/Desktop/file.txt");
System.out.println(HW09.primeCounter(file));
}
catch (IOException e) {
System.out.println("Couldn't find file! ");
}
}
}
I see a number of issues with your current code, first and foremost is the lack of separation of concerns. I would start with a simple method to determine if a single number is prime. I wrote such a method here, and that looks like
private static boolean isPrime(int n) {
if (n == 2) {
return true;
} else if (n == 1 || n % 2 == 0) {
return false;
}
for (int i = 3; i * i <= n; i += 2) {
if (n % i == 0) {
return false;
}
}
return true;
}
Then you want to read numbers with your Scanner. And check if they are prime. And don't forget to close the Scanner when you're done. Using a try-with-resources takes care of that. Like,
public static int primeCounter(String fileName) throws IOException {
int count = 0;
try (Scanner s = new Scanner(new File(fileName))) {
while (s.hasNextInt()) {
int v = s.nextInt();
if (isPrime(v)) {
count++;
}
}
}
return count;
}
Finally, when constructing a path, it's better to use the system properties to get the home folder. That way, it can work on other people's machines more easily,
public static void main(String args[]) {
try {
String file = new File(
System.getProperty("user.home"), "Desktop/file.txt").getPath();
System.out.println(primeCounter(file));
} catch (IOException e) {
System.out.println("Couldn't find file! ");
}
}
And I created a file to test against,
$ cat ~/Desktop/file.txt
13
11
7
5
3
2
4
After running the program I get, as expected,
6
I want to incrementally process the text written to an OutputStream as it is written.
For example, suppose we have this program:
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
public class Streaming {
// Writes file, incrementally, to OutputStream.
static void dump(File file, OutputStream out) throws IOException {
// Implementation omitted
}
static int sum = 0;
public static void main(String[] args) throws IOException {
Charset charSet = Charset.defaultCharset(); // Interpret the file as having this encoding.
dump(new File("file.txt"), new OutputStream() {
#Override
public void write(int b) throws IOException {
// Add b to bytes already read,
// Determine if we have reached the end of the token (using
// the default encoding),
// And parse the token and add it to `sum`
}
});
System.out.println("Sum: " + sum);
}
}
Suppose file.txt is a text file containing a space-delimited list of ints. In this program, I wish to find the sum of the ints in file.txt, accumulating the sum in the sum variable. I would like to avoid building up a String that is millions of characters long.
I'm interested in a way that I can accomplish this using the dump function, which writes the contents of a file to an output stream. I'm not interested in reading the file in another way (e.g. creating a Scanner for file.txt and repeatedly calling nextInt on the scanner). I'm imposing this restriction because I'm using a library that has an API similar to dump, where the client must provide an OutputStream, and the library subsequently writes a lot of text to the output stream.
How can I implement the write method to correctly perform the steps as outlined? I would like to avoid doing the tokenization by hand, since utilities like Scanner are already capable of doing tokenization, and I want to be able to handle any encoding of text (as specified by charSet). However, I can't use Scanner directly, because there's no way of checking (in a non-blocking way) if a token is available:
public static void main(String[] args) throws IOException {
Charset charSet = Charset.defaultCharset();
PipedInputStream in = new PipedInputStream();
try (Scanner sc = new Scanner(in, charSet)) {
dump(new File("file.txt"), new PipedOutputStream(in) {
#Override
public void write(byte[] b, int off, int len) throws IOException {
super.write(b, off, len);
// This will loop infinitely, because `hasNextInt`
// will block if there is no int token currently available.
if (sc.hasNextInt()) {
sum += sc.nextInt();
}
}
});
}
System.out.println("Sum: " + sum);
System.out.println(charSet);
}
Is there a non-blocking utility that can perform the tokenization for me as data is written to the output stream?
If I understand your question correctly, FilterOutputStream is what you want to subclass. DigestOutputStream extends FilterOutputStream and does something somewhat similar to what you want to do: it monitors the bytes as they come through and passes them to a different class for processing.
One solution that comes to mind is for the FilterOutputStream to pass the bytes to a PipedOutputStream, connected to a PipedInputStream which a different thread reads in order to create your sum:
PipedOutputStream sumSink = new PipedOutputStream();
Callable<Long> sumCalculator = new Callable<Long>() {
#Override
public Long call()
throws IOException {
long sum = 0;
PipedInputStream source = new PipedInputStream(sumSink);
try (Scanner scanner = new Scanner(source, charSet)) {
while (scanner.hasNextInt()) {
sum += scanner.nextInt();
}
}
return sum;
}
};
Future<Long> sumTask = ForkJoinPool.commonPool().submit(sumCalculator);
OutputStream dest = getTrueDestinationOutputStream();
dest = new FilterOutputStream(dest) {
#Override
public void write(int b)
throws IOException {
super.write(b);
sumSink.write(b);
}
#Override
public void write(byte[] b)
throws IOException {
super.write(b);
sumSink.write(b);
}
#Override
public void write(byte[] b,
int offset,
int len)
throws IOException {
super.write(b, offset, len);
sumSink.write(b, offset, len);
}
#Override
public void flush()
throws IOException {
super.flush();
sumSink.flush();
}
#Override
public void close()
throws IOException {
super.close();
sumSink.close();
}
};
dump(file, dest);
long sum = sumTask.get();
As "idiomatic" approach, you might want a FilterOutputStream:
These streams sit on top of an already existing output stream (the underlying output stream) which it uses as its basic sink of data, but possibly transforming the data along the way or providing additional functionality.
At least to me, it sounds something like what you describe.
It is a concrete class (unlike OutputStream), so the absolute minimum you can get away with is to provide your constructor and an implementation for the single-byte write() (which is going to be invoked by the default implementations of other write() methods):
public class SumOutputStream extends FilterOutputStream {
public int sum = 0;
public SumOutputStream(OutputStream os) {
super(os);
}
private int num = 0;
public void write(int b) throws IOException {
if (b >= '0' && b <= '9') {
sum -= num;
num = num * 10 + b - '0';
sum += num;
} else {
num = 0;
}
out.write(b);
}
public static void main(String[] args) throws IOException {
try (SumOutputStream sos = new SumOutputStream(new FileOutputStream("test.txt"))) {
sos.write("123 456 78".getBytes());
System.out.println(sos.sum);
sos.write('9');
System.out.println(sos.sum);
}
}
}
This will sum whatever numbers are passing, keeping sum up to date all the time even with partial results (that is what separating the 9 is supposed to show).
Based off #tevemadar's answer. Reads in strings and tries to parse them to ints. If that fails, then you know the number is done and is then added to the sum. The only problem is that my method doesn't add the last number if it occupies the last two bytes. To solve this, you could add a single line method: if(!currNumber.isEmpty()) sum += Integer.parseInt(currNumber); that you can call once the file finishes.
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Objects;
class SumOutputStream extends FilterOutputStream {
public int sum = 0;
String currNumber = "";
String lastChar = "";
public SumOutputStream(OutputStream os){
super(os);
}
public void write(byte b[], int off, int len) throws IOException {
Objects.checkFromIndexSize(off, len, b.length);
for (int i = 0 ; i < len ; i++) {
try {
if(!lastChar.isEmpty()) {
Integer.parseInt(lastChar);
currNumber += lastChar;
}
} catch(NumberFormatException e) {
if(!currNumber.isEmpty()) sum += Integer.parseInt(currNumber);
currNumber = "";
} catch(NullPointerException e) {
e.printStackTrace();
}
write(b[off + i]);
lastChar = new String(b);
}
}
}
i'm trying to write a program that reads a file and then prints it out and then reads it again but only prints out the lines that begin with "The " the second time around. it DOES print out the contents of the file, but then it doesn't print out the lines that begin with "The " and i can't figure out why. it prints out the println line right before the loop, but then it ignores the for-loop completely. the only difference between my findThe method and my OutputTheArray method is the substring part, so i think that's the problem area but i don't know how to fix it.
import java.util.*;
import java.io.*;
public class EZD_readingFiles
{
public static int inputToArray(String fr[], Scanner sf)
{
int max = -1;
while(sf.hasNext())
{
max++;
fr[max] = sf.nextLine();
}
return max;
}
public static void findThe(String fr[], int max)
{
System.out.println("\nHere are the lines that begin with \"The\": \n");
for(int b = 0; b <= max; b++)
{
String s = fr[b].substring(0,4);
if(s.equals("The "))
{
System.out.println(fr[b]);
}
}
}
public static void OutputTheArray(String fr[], int max)
{
System.out.println("Here is the original file: \n");
for(int a = 0; a <= max; a++)
{
System.out.println(fr[a]);
}
}
public static void main(String args[]) throws IOException
{
Scanner sf = new Scanner(new File("EZD_readme.txt"));
String fr[] = new String[5];
int y = EZD_readingFiles.inputToArray(fr,sf);
EZD_readingFiles.OutputTheArray(fr,y);
int z = EZD_readingFiles.inputToArray(fr,sf);
EZD_readingFiles.findThe(fr,z);
sf.close();
}
}
this is my text file with the tester data (EZD_readme.txt):
Every man tries as hard as he can.
The best way is this way.
The schedule is very good.
Cosmo Kramer is a doofus.
The best movie was cancelled.
Try cloning sf and passing it to the other function.
Something like this:
Scanner sf = new Scanner(new File("EZD_readme.txt"));
Scanner sf1 = sf.clone();
int y = EZD_readingFiles.inputToArray(fr,sf);
EZD_readingFiles.OutputTheArray(fr,y);
int z = EZD_readingFiles.inputToArray(fr,sf1);
EZD_readingFiles.findThe(fr,z);
sf.close();
sf1.close();
I want to take an input from a txt file and put all the characters to the array so I can perform on it some regex functions. But when I try to read the array with a single loop to check it, nothing appears. What is wrong here?
import java.io.BufferedReader;
import java.io.FileReader;
public class Main
{
public static void main(String[] args)
{
try
{
Task2.doTask2();
}catch(Exception e){};
}
}
class Task2
{
public static void doTask2() throws Exception
{
FileReader fr = new FileReader("F:\\Filip\\TextTask2.txt");
BufferedReader br = new BufferedReader(fr);
char[] sentence = null;
int i;
int j = 0;
while((i = br.read()) != -1)
{
sentence[j] = (char)i;
j++;
}
for(int g = 0; g < sentence.length; g++)
{
System.out.print(sentence[g]);
}
br.close();
fr.close();
}
}
You can read a file simply using File.readAllBytes. Then it's not necessary to create separate readers.
String text = new String(
Files.readAllBytes(Paths.get("F:\\Filip\\TextTask2.txt"))
);
In the original snippet, the file reading function is throwing a NullPointerException because sentence was initialized to null and then dereferenced: sentence[j] = (char)i;
The exception was swallowed by the calling function and not printed, which is why you're not seeing it when you run the program: }catch(Exception e){};
Instead of swallowing the exception declare the calling function as throwing the appropriate checked exception. That way you'll see the stack trace when you run it: public static void main(String[] args) throws IOException {
You are using wrong index , use "g" instead of "i" here.:
System.out.println(sentence[g]);
Also, the best and simplest way to do this is:
package io;
import java.nio.file.*;;
public class ReadTextAsString
{
public static String readFileAsString(String fileName)throws Exception
{
return new String(Files.readAllBytes(Paths.get(fileName)));
}
public static void main(String[] args) throws Exception
{
String data = readFileAsString("F:\\Filip\\TextTask2.txt");
System.out.println(data); //or iterate through data if you want to print each character.
}
}
I'm programming in Java. I'm not good at programming, but I'm trying.
I managed to create a file that generates an array of 10k random (in range 1 through 1 million) numbers into a text file. This class is called 'CreateDataFile'
What I'm trying to do now is read the array from the text file created in 'CreateDataFile' from a completely different class. This new class is called 'ProcessDataFile'
The first thing I thought about doing is 'extends' the class. So both classes communicate.
The thing is, I know how to create a for loop in a program and then find the largest number. I just don't understand how to read this text file, and create a for loop that processes from the text file and finds the max value.
Here's my CreateDataFile class
import java.io.*;
import java.util.Random;
public class CreateDataFile {
public static void main(String[] args) {
int [] integers = new int[10000];
Random r = new Random();
try{
PrintWriter p = new PrintWriter("dataset529.txt");
for (int i = 0; i <integers.length; i++) {
int number = r.nextInt(1000000)+1;
p.print(" " + number);
}
p.close();
}
catch (IOException e)
{
e.printStackTrace();
}
}
}
Now this generates the numbers I need into a text file called dataset529.
If everything was in one class, I'd just create a for loop.. something like
int max = integers[0];
for(int i = 0; i<integers.length; i++){
if (integers[i] > max)
System.out.println(integers[i]);
}
But as I'm creating my ProcessDataFile class, I'm having a hard time reading the text file created from the CreateDataFile class.
Any ideas on how I can read this text file and run a for loop over it to find the max number like I used above?
Thanks, any help would be appreciated.
First of all, you should write in the file each number on one line so that it's easier when you read the numbers from the file. This can be done just by doing:
p.print(number + "\n");
After that, you can use this code to get the max of all the numbers:
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
public class ProcessDataFile {
public static void main(String[] args) throws IOException {
String fileName = "dataset529.txt";
String temp;
int max = Integer.MIN_VALUE;
int i = 0;
int[] numbers = new int[10000];
try (BufferedReader br = new BufferedReader(new FileReader(fileName))) {
while((temp = br.readLine()) != null) {
if(temp.isEmpty())
break;
numbers[i++] = Integer.parseInt(temp);
}
}
for(i = 0; i < numbers.length; i++)
if(max < numbers[i])
max = numbers[i];
System.out.println(max);
}
Write the content of each number on new line. While reading the file, maintain a max element.
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Random;
public class CreateDataFile {
public static void main(String[] args) {
int[] integers = new int[10000];
Random r = new Random();
try {
PrintWriter p = new PrintWriter("dataset529.txt");
for (int i = 0; i < integers.length; i++) {
int number = r.nextInt(1000000) + 1;
p.print(number + "\n");
}
p.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
Now read the file line by line.
public class ProcessDataFile {
public static void main(String[] args) throws IOException {
int max = Integer.MIN_VALUE;
String line = null;
BufferedReader br = new BufferedReader(new FileReader("dataset529.txt"));
while ((line = br.readLine()) != null) {
int num = Integer.parseInt(line);
if (max < num) {
max = num;
}
}
}
System.out.println(max);
}