Hackerrank Dynamic Array Timeout - java

I was working on the Data Structures track on Hackerrank, when I came across this challenge.
I think my code works, but I am getting timeout issues. That is, it seems to be taking too long to run on inputs with a lot of queries. Here is my first shot at a solution (with the timeout issues):
import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;
public class Solution {
public static void main(String[] args) {
/* Enter your code here. Read input from STDIN. Print output to STDOUT. Your class should be named Solution. */
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int q = sc.nextInt();
ArrayList<Integer>[] group = (ArrayList<Integer>[])new ArrayList[n];
int lastAns = 0;
ArrayList<Integer> curr = null;
//int currVal = 0;
for(int i = 0;i < q;i++){
int query = sc.nextInt();
int x = sc.nextInt();
int y = sc.nextInt();
int thing = (x^lastAns) % n;
if(query == 1){
if(group[thing] == null){
group[thing] = new ArrayList<Integer>(n);
}
curr = group[thing];
curr.add(y);
}else if(query == 2){
curr = group[thing];
lastAns = curr.get(y % curr.size());
System.out.println(lastAns);
}
}
sc.close();
}
}
Here is code that worked with no timeout issues:
import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;
public class Solution {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int q = sc.nextInt();
int lastAns = 0;
ArrayList<ArrayList> group = new ArrayList();
ArrayList<Integer> curr = null;
//int currVal = 0;
for (int i = 0; i < n; i++){
group.add(new ArrayList<Integer>());
}
for(int i = 0;i < q;i++){
int query = sc.nextInt();
int x = sc.nextInt();
int y = sc.nextInt();
int thing = (x^lastAns) % n;
if(query == 1){
curr = group.get(thing);
curr.add(y);
}else if(query == 2){
curr = group.get(thing);
lastAns = curr.get(y % curr.size());
System.out.println(lastAns);
}
}
sc.close();
}
}
My question is: What is the difference here that resolved the timeout issues? My first guess is that arrays take longer to access/change elements than ArrayLists. Is this the case?

The key difference I see is that in the poorly-performing code, you're giving each inner ArrayList<Integer> an initial size of n, whereas in the other code you're only giving that initial size to the outer list:
group[thing] = new ArrayList<Integer>(n);
vs
group.add(new ArrayList<Integer>());
I'm guessing this was a mistake, and by forcing each of the inner lists to have size n you're making the memory space required by this algorithm O(n²).

Related

Java Deque (Finding the max number of unique integers from subarrays.)

I was trying to solve a HackerRank problem on Java Deque. My code passed all the cases apart from the ones which have 100,000 inputs.
Problem: In this problem, you are given N integers. You need to find the maximum number of unique integers among all the possible contiguous subarrays of size M.
--->So we wre given N integers, and need to find the number of "unique integers" in each contagious subarray(of size M). And then print the maximum number of those "unique Integers".
link: https://www.hackerrank.com/challenges/java-dequeue/problem
My Code:
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
Deque deque = new ArrayDeque<>();
HashSet<Integer> set = new HashSet<>();
int n = in.nextInt();
int m = in.nextInt();
int max=0;
for (int i = 0; i < n; i++) {
int num = in.nextInt();
deque.add(num);
set.add(num);
if(i>=m-1){
if(set.size()>max)max=set.size();
Integer removed=(Integer)deque.removeFirst();
set.remove(removed);
set.add((Integer)deque.peek());
}
}
System.out.println(max);
}
Please tell me where my code went wrong.
What is the point of this line?
set.add((Integer)deque.peek());
I don't see anything in your code that is slow. I just wonder how you can keep track of unique numbers by using a set, given that a set only tells you if there is such a number (but not how many occurrences of the same number there are). And you don't want to keep scanning the deque to see if the number being removed is the last one.
I don't think this is great/fast code, but it seems to pass the test-cases. I keep a count of how many of each integer there is in the window by using a map (and use some of your code).
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
Deque<Integer> deque = new ArrayDeque<>();
HashMap<Integer, Integer> counts = new HashMap<>();
int n = in.nextInt();
int m = in.nextInt();
int max = 0;
for (int i = 0; i < n; i++) {
int num = in.nextInt();
deque.add(num);
int count = counts.getOrDefault(num, 0);
counts.put(num, ++count);
if (i >= m - 1) {
if (counts.size() > max) max = counts.size();
Integer removed = deque.removeFirst();
int removing = counts.get(removed);
removing--;
if (removing == 0) {
counts.remove(removed);
} else {
counts.put(removed, removing);
}
}
}
System.out.println(max);
}
}
Just wanted to share how I solved it in case it helps.
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
Deque deque = new ArrayDeque();
Set<Integer> integers = new HashSet<>();
int n = in.nextInt();
int m = in.nextInt();
long result = 0;
for (int i = 0; i < n; i++) {
int num = in.nextInt();
deque.add(num);
integers.add(num);
if (deque.size() == m) {
long currentSize = integers.size();
if (currentSize > result) {
result = currentSize;
}
Integer removed = (Integer) deque.pollFirst();
if (!deque.contains(removed)) {
integers.remove(removed);
}
}
}
System.out.println(result);
}
We can optimize the space a little bit by avoiding the hashmap all together, but it seems like Hackerrank does not care about that. Any how I am putting my solution here which can solve this problem by using using a map.
private int countUniqueNumsInSubarrays(int[] nums, int m) {
Deque<Integer> deque = new LinkedList<>();
int maxUniqueCount = 0;
for (int i = 0; i < nums.length; i++) {
// if deque's left entry is outside the window then pop it out
while (!deque.isEmpty() && i - deque.peekFirst() >= m) {
deque.removeFirst();
}
// this will make sure that the deque only contains unique numbers,
// this is essentially helps us avoid that extra hash map
while (!deque.isEmpty() && nums[deque.peekLast()] == nums[i]) {
deque.removeLast();
}
deque.addLast(i);
if (i >= m - 1) {
maxUniqueCount = Math.max(maxUniqueCount, deque.size());
}
}
return maxUniqueCount;
}
import java.io.*;
import java.util.*;
import java.util.stream.Stream;
public class Solution {
public static void main(String[] args) {
var sc = new Scanner(System.in);
var split = sc.nextLine().split(" ");
int n = Integer.parseInt(split[0]);
int m = Integer.parseInt(split[1]);
if (!(1 <= n && n <= 100_000)) {
System.exit(0);
}
if (!(1 <= m && m <= 100_000)) {
System.exit(0);
}
if (!(m <= n)) {
System.exit(0);
}
split = sc.nextLine().split(" ");
sc.close();
int maxNumUniqueInt = 0;
HashSet<Integer> dist = new HashSet<>();
Deque<Integer> deque = new ArrayDeque<>();
int[] arr = Stream.of(split).mapToInt(Integer::parseInt).toArray();
for (int i = 0; i < m; i++) {
deque.addLast(arr[i]);
dist.add(arr[i]);
}
int num = dist.size();
if (maxNumUniqueInt < num) {
maxNumUniqueInt = num;
}
for (int i = m; i < n; i++) {
deque.addLast(arr[i]);
dist.add(arr[i]);
int remove = deque.removeFirst();
if (!deque.contains(remove)) {
dist.remove(remove);
}
num = dist.size();
if (maxNumUniqueInt < num) {
maxNumUniqueInt = num;
}
// System.out.println(i + " | " + deque + " | " + dist + " | " + maxNumUniqueInt);
}
System.out.println(maxNumUniqueInt);
}
}
import java.util.*;
public class test {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
Deque<Integer> deque = new ArrayDeque<>();
int n = in.nextInt();
int m = in.nextInt();
int maxUnique = 0;
Map<Integer, Boolean> uniqSet = new HashMap<>();
for (int i = 0; i < n; i++) {
int num = in.nextInt();
deque.addLast(num);
uniqSet.put(num, true);
if(deque.size() == m){
// int uniqueSize = new HashSet<>(deque).size();
int uniqueSize = uniqSet.size();
maxUnique = Math.max(maxUnique, uniqueSize);
int x = deque.removeFirst();
if(!deque.contains(x)){
uniqSet.remove(x);
}
}
}
in.close();
System.out.println(maxUnique);
}
}

Is there any way to fix my main class for my adjacency list graph?

So basically I'm suppose to take the numbers from a file Ex.
And turn it into this Ex.
We're suppose to make a graph class and store a adjacency list representation of a graph. We're also suppose to do it with an array of arraylists. So I got some help making the graph class and I'm making it so that the users file is processed through the graph class but for some reason there's an error and the output isn't right. Can someone help with this?
Graph Class
import java.util.ArrayList;
public class Graph {
ArrayList<Integer> [] nodes;
int n_nodes;
public Graph(int numberNodes){
this.nodes = new ArrayList[numberNodes+1];
this.n_nodes = numberNodes;
for(int i = 0; i < n_nodes + 1; i++){
nodes[i] = new ArrayList<>();
}
}
public void addNeighbor(int node, int neighbor){
nodes[node].add(neighbor);
}
public String toString(){
StringBuilder myGraph = new StringBuilder();
for(int i = 1; i < nodes.length; i++){
myGraph.append(i);
ArrayList<Integer> neighbors = nodes[i];
int totalNeighbors = neighbors.size();
for(int j = 0; j < totalNeighbors; j++){
int myneighbor = neighbors.get(j);
myGraph.append(" -> " + myneighbor);
}
myGraph.append('\n');
}
return myGraph.toString();
}}
Main Class
import java.io.File;
import java.io.IOException;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Program1 {
public static void main(String[] args) throws IOException {
File file = null;
JFileChooser chooser = new JFileChooser();
Scanner ans = new Scanner(System.in);
int result = chooser.showOpenDialog(null);
if (result == JFileChooser.APPROVE_OPTION) {
file = chooser.getSelectedFile();
} else {
JOptionPane.showMessageDialog(null, "No File Selected");
System.exit(1);
}
Scanner input = new Scanner(file);
int y = input.nextInt();
int x = 0;
Graph graph = new Graph(y);
while (input.hasNextLine()) {
for (int i = 0; i < y; i++) {
x = input.nextInt();
graph.addNeighbor(i, x);
}
System.out.println(graph.toString());
}
}}
Also I'm new to the whole stackoverflow website so sorry if my wording isn't clear or my code isn't formatted good enough.
Edit
This is the error it's showing
As 3 as read by
int y = input.nextInt();
is on a different line then you need to read the CR-LF as well.
Personally I would use the following paradigm
str = input.nextLine ()
// convert to int
while (input.hasNextLine) {
str = input.nextLine ()
arr[] = str.split (" ");
// loop through length of arr - in your code `y` is not updated
add arr[x] to graph
so basically you want something like
Scanner input = new Scanner(file);
String line = input.nextLine();
int y = 0;
if (line != null) {
y = Integer.parseInt(line.trim());
}
Graph graph = new Graph(y);
while (input.hasNextLine() && y > 0) {
if (input.hasNextLine()) {
line = input.nextLine();
}
String nums[] = line.split(" ");
for (int i = 0; i < nums.length; i++) {
int x = Integer.parseInt(nums[i]);
graph.addNeighbor(i, x);
}
System.out.println(graph.toString());
}

Scanner throwing java.util.NoSuchElementException when input is taken

This code below throws NoSuchElementException in the function aVeryBigSum.
PS: This is task from hackerrank so I can only modify the code in function: aVeryBigSum.
This function takes the following inputs: n which is the number of elements in an array to be added, and the elements of array.
import java.io.*;
import java.math.*;
import java.security.*;
import java.text.*;
import java.util.*;
import java.util.concurrent.*;
import java.util.regex.*;
public class Solution {
// Complete the aVeryBigSum function below.
static long aVeryBigSum(long[] ar) {
int n, sum = 0;
Scanner read = new Scanner(System.in);
n = read.nextInt();
for(int i = 0; i < n; i++)
sum += read.nextLong();
return sum;
}
private static final Scanner scanner = new Scanner(System.in);
public static void main(String[] args) throws IOException {
BufferedWriter bufferedWriter
= new BufferedWriter(new FileWriter(System.getenv("OUTPUT_PATH")));
int arCount = scanner.nextInt();
scanner.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
long[] ar = new long[arCount];
String[] arItems = scanner.nextLine().split(" ");
scanner.skip("(\r\n|[\n\r\u2028\u2029\u0085])?");
for (int i = 0; i < arCount; i++) {
long arItem = Long.parseLong(arItems[i]);
ar[i] = arItem;
}
long result = aVeryBigSum(ar);
bufferedWriter.write(String.valueOf(result));
bufferedWriter.newLine();
bufferedWriter.close();
scanner.close();
}
}
Output:
Why are you reading from Scanner in your aVeryBigSum method?
Just loop through ar argument and calculate sum.
static long aVeryBigSum(long[] ar) {
long _sum = 0;
for(int i=0; i < ar.length; i++)
sum += ar[i];
return _sum;
}
static long aVeryBigSum(long[] ar) {
int n;
Long sum = 0;
Scanner read = new Scanner(System.in);
n = read.nextInt();
for(int i = 0; i < n; i++)
sum += read.nextLong();
return sum;
}
its working fine for me if you change: int n;
long sum=0; in existing code and try.
output:2
1 2
5
1000000001
1000000002
1000000003
1000000004
1000000005
5000000015

Java using scanner input a txt to a 2 dimensional array

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.Scanner;
public class test{
public static final int SIZE = 30;
public static final int DUE_DATE = 15;
public static final int TASK_NUMBER = 30;
public static void main(String[] args)throws FileNotFoundException{
Scanner console = new Scanner(System.in);
System.out.println("Enter input file: ");
String inputCompletionName = console.next();
boolean[][] completion = new boolean[TASK_NUMBER][SIZE];
File inputCompletion = new File(inputCompletionName);
Scanner in = new Scanner(inputCompletion);
int i = 0, j = 0;
for(j = 0; j < SIZE; j++){
for(i = 0; i < TASK_NUMBER; i++){
while(in.hasNextBoolean()){
boolean input = in.nextBoolean();
completion[i][j] = input;
}
System.out.println(completion[i][j]);
}
}
}
I tried this code. My input is some boolean value but the output only have first element. Really don't know how to fix this.
My input file is just some random boolean values like this.
true
false
true
false
true
But the output only shows the first element.
The problem is this:
while(in.hasNextBoolean()) {
boolean input = in.nextBoolean();
completion[i][j] = input;
}
And that is inside your 2 for loops, so you read your booleans into the same grid cell.
This will work:
for(j = 0; j < SIZE && in.hasNextBoolean(); j++){
for(i = 0; i < TASK_NUMBER && in.hasNextBoolean(); i++){
boolean input = in.nextBoolean();
completion[i][j] = input;
System.out.println(completion[i][j]);
}
}

Which is the most efficient way of taking input in Java?

I am solving this question.
This is my code:
import java.io.IOException;
import java.util.Scanner;
public class Main {
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int k = sc.nextInt();
int[] t = new int[n];
int count = 0;
for (int i = 0; i < n; i++) {
t[i] = sc.nextInt();
if (t[i] % k == 0) {
count++;
}
}
System.out.println(count);
}
}
But when I submit it, it get's timed out. Please help me optimize this to as much as is possible.
Example
Input:
7 3
1
51
966369
7
9
999996
11
Output:
4
They say :
You are expected to be able to process
at least 2.5MB of input data per
second at runtime.
Modified CODE
Thank you all...I modified my code and it worked...here it is....
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] input = br.readLine().split(" ");
int n = Integer.parseInt(input[0]);
int k = Integer.parseInt(input[1]);
int count = 0;
for (int i = 0; i < n; i++) {
if (Integer.parseInt(br.readLine()) % k == 0) {
count++;
}
}
System.out.println(count);
}
regards
shahensha
This could be slightly faster, based on limc's solution, BufferedReader should be faster still though.
import java.io.IOException;
import java.util.Scanner;
public class Main {
public static void main(String[] args) throws IOException {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int k = sc.nextInt();
int count = 0;
while (true) {
try {
if (sc.nextInt() % k == 0) {
count++;
}
} catch (NoSuchElementException e) {
break;
}
}
System.out.println(count);
}
}
How about this?
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int k = sc.nextInt();
int count = 0;
for (int i = 0; i < n; i++) {
if (sc.nextInt() % k == 0) {
count++;
}
}
System.out.println(count);
You may consider reading big chunks of input and then get the numbers from there.
Other change is, you may use Integer.parseInt() instead of Scanner.nextInt() although I don't know the details of each one, somethings tells me Scanner version performs a bit more computation to know if the input is correct. Another alternative is to convert the number yourself ( although Integer.parseInt should be fast enough )
Create a sample input, and measure your code, change a bit here and there and see what the difference is.
Measure, measure!
BufferedReader is supposed to be faster than Scanner. You will need to parse everything yourself though and depending on your implementation it could be worse.

Categories

Resources