Finding a 2D array inside a bigger 2D array - java

I am able to solve the problem for those test cases where there is only 1 string per row.But i fail if there are multiple strings in a single row.
For example:
Test Case Type 1:
Big matrix:
7283455864
6731158619
8988242643
3830589324
2229505813
5633845374
6473530293
7053106601
0834282956
4607924137
Small Matrix:
9505
3845
3530
I pass these kinds of test cases as 9505 occurs at most 1 time inside Big Matrix.
Test Case Type:2
Big Matrix:
7652157548860692421022503
9283597467877865303553675
4160389485250089289309493
2583470721457150497569300
3220130778636571709490905
3588873017660047694725749
9288991387848870159567061
4840101673383478700737237
8430916536880190158229898
8986106490042260460547150
2591460395957631878779378
1816190871689680423501920
0704047294563387014281341
8544774664056811258209321
9609294756392563447060526
0170173859593369054590795
6088985673796975810221577
7738800757919472437622349
5474120045253009653348388
3930491401877849249410013
1486477041403746396925337
2955579022827592919878713
2625547961868100985291514
3673299809851325174555652
4533398973801647859680907
Small Matrix:
5250
1457
8636
7660
7848
I fail these kinds of test cases where 5250(or any other row in small matrix) occurs more than once inside same row of bigger matrix:
Below is the code i have written:
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) {
HashMap<Integer,Integer> rowCol=new HashMap();
Scanner in = new Scanner(System.in);
int t = in.nextInt();
for(int a0 = 0; a0 < t; a0++){
//bigger array
int R = in.nextInt();
int C = in.nextInt();
String G[] = new String[R];
for(int G_i=0; G_i < R; G_i++){
G[G_i] = in.next();
}
//smaller array
int r = in.nextInt();
int c = in.nextInt();
String P[] = new String[r];
for(int P_i=0; P_i < r; P_i++){
P[P_i] = in.next();
}
for(int i = 0;i<R-r;i++)//obvious
{
for(int j = 0; j<r;j++ )//obvious
{
//if string found put in map(row at which found,column at whch found)
if(G[i].indexOf(P[j])>=0)//string found
{
rowCol.put(i,G[i].indexOf(P[j]));
}
}
}
//now check if rows are consecutive(1,2,3) and columns are equal(1,1,1)
HashSet<Integer> mc = new HashSet<Integer>(rowCol.values());//if size==1 then same column
ArrayList<Integer> mr = new ArrayList<Integer>(rowCol.keySet());
int count = 0;
for(int m = 0 ;m<mr.size()-1;m++)//checking if keys are consecutive
{
if(mr.get(m)+1==mr.get(m+1))
{
count++;//how many values are same ,hw mny strings found at same index
}
}
//System.out.println(count+"+++++"+(mr.size()-1));
//System.out.println( rowCol.values().size()+"==="+r);
if(mc.size()==1 && count==(mr.size()-1) && rowCol.keySet().size()==r)//all column same && all rows are consecutive &&
{
System.out.println("YES");
}
else
{
System.out.println("NO");
}
}
}
}

Your logic is faulty.
for(int i = 0;i<R-r;i++)//obvious
{
for(int j = 0; j<r;j++ )//obvious
{
//if string found put in map(row at which found,column at whch found)
if(G[i].indexOf(P[j])>=0)//string found
{
rowCol.put(i,G[i].indexOf(P[j]));
}
}
}
This goes through all the lines in G, and all the lines of P. If that line of P exists in that line of G, it will be placed in the map.
But first, it only tells you that some line from P is in that line of G, it doesn't tell you which line. This will mean it also fails when you are looking for a small matrix which is just like an existing matrix but different order of lines.
Second, if there is more than one line of the small matrix in the line of G, it will keep the index of the lower line from P. That is, if you have both 5250 and 7660 in the same line in G, it will keep just the index of the 7660 and ignore the 5250.
ArrayList<Integer> mr = new ArrayList<Integer>(rowCol.keySet());
You are using mr to check for consecutive line, but you are filling it with the key set from a HashMap. This means that the order is not guaranteed - you could get the line numbers in the order 5,3,1,2,4 or whatever.
You should write your program with different logic. Don't try to collect all the locations of all the lines. Find the location of the first line of P, and immediately check if the rest are in place. Say you found the first line of P in line 30 at index 15. Then check if line 2 is in line 31 at index 15, and if line 3 is in line 32 at index 15, and so on.
If all matched, print "YES", and return from the method. Do not continue the loop. But if not all matched, keep looking for P[0].
Note that there may be more than one occurrence of P[0] in the same line in G. So if matching failed, continue to search in the same line of G until no more occurrences of P[0] occur, and only then move to the next line of G.
If you didn't find any matches, then at the end of the loop you can print "NO".

Related

Reading a string splitting it and assigning values to 2D array in JAVA

I am trying to split a string with " "(space) and assigning each value on row to each respective array.
The input file contains:
4
2 2
1 3
4 7
3 4
The first line of the file has a single integer value N which is number of jobs.
The next N lines will represent a job, each with 2 values.
How do I start reading from second line from a Input file?
I want to split from Second line and assign it to 2D array. So if (2,2) is there on second line, then 2 should be assigned to array[0][0] and the other 2 to array[0][1]. For next line 1 should be assigned to array[1][0] and 3 should be assigned to array[1][1].
int num = scan.nextInt(); // taking number of jobs from first line
int[][] array = new int[num][num];
while (scan.hasNext()) //It reads till file has next line
{
String str = scan.nextLine();
for (int i = 0; i < num; i++) {
for (int j = 0; j < num; j++) {
array[i][j] = scan.nextInt();
}
}
}
Had done till here, couldn't figure out further.
int[][] array = new int[num][num];
Wrong dimensions of the array, for N = 4 you create array of 4 * 4, not 4 * 2.
Since the number of columns is fixed in your case, you should create array as new int[num][2] and update reading of the data accordingly.
String str = scan.nextLine();
for (int i = 0; i < num; i++) {
for (int j = 0; j < num; j++) {
array[i][j] = scan.nextInt();
}
}
Reading a line just to skip it may be redundant if you use Scanner to read the integer numbers using nextInt. So actually you do NOT need to read the data line by line, then split each line into String parts, and convert each part into a number because Scanner class takes care of it.
Also, the innermost loop tries to read N numbers per array row, while it's better to refer actual length of the array in the row.
Thus, it should be ok just to read the data according to the task using Scanner only:
int num = scan.nextInt(); // taking number of jobs from the first line
// preparing array of N rows and 2 columns
int[][] array = new int[num][2];
for (int i = 0; i < num; i++) {
for (int j = 0; j < array[i].length; j++) { // reading 2 ints per row
array[i][j] = scan.nextInt();
}
}
You can make it a lot easier by just ignoring the first line and letting Java do the hard work:
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.stream.Stream;
import java.util.Arrays;
public class FileToArray {
public static void main(String[] args) {
try {
try (Stream<String> stream = Files.lines(Path.of("arr.txt"))) {
String[][] nums = stream.skip(1).map(s -> s.split(" ")).toArray(String[][]::new);
System.out.println(Arrays.deepToString(nums));
}
} catch (Throwable t) {
t.printStackTrace();
}
}
}

Why am I getting Time Limit Exceeded (TLE) error when using ArrayList<String[]> instead of int[][]?

So I was trying to implement the Floyd-Warshal algorithm for shortest distance pairs. My first implementation of the algorithm lead to time limit exceeded while the second version using a 2d array was successful. Can anyone point out why is the TLE coming in the first implementation?
Note: 1000000 = infinity
Input:
The first line of input contains an integer T denoting the no of test cases. Then T test cases follow. The first line of each test case contains an integer V denoting the size of the adjacency matrix. The next V lines contain V space separated values of the matrix (graph). All input will be integer type.
Output:
For each test case output will be V*V space separated integers where the i-jth integer denote the shortest distance of ith vertex from jth vertex. For INT_MAX integers output INF.
Sample Input:
2
2
0 25
10000000 0
3
0 1 43
1 0 6
10000000 10000000 0
Sample Output:
0 25
INF 0
0 1 7
1 0 6
INF INF 0
Code approach 1 (giving TLE):
/*package whatever //do not write package name here */
import java.util.*;
import java.lang.*;
import java.io.*;
class GFG {
public static int parseInt(String no){
if(no.equals("10000000") || no.equals("INF")){
return Integer.MAX_VALUE;
}
else
return Integer.parseInt(no);
}
public static void main (String[] args) {
Scanner sc = new Scanner(System.in);
StringBuffer sb = new StringBuffer();
int t = Integer.parseInt(sc.nextLine());
while(t-->0){
int n = Integer.parseInt(sc.nextLine());
ArrayList<String[]> adj = new ArrayList<>(n);
for(int i=0;i<n;++i){
String[] input = sc.nextLine().split(" ");
adj.add(input);
}
for(int k=0;k<n;++k){
for(int i=0;i<n;++i){
for(int j=0;j<n;++j){
int cur = parseInt(adj.get(i)[j]);
int iToK = parseInt(adj.get(i)[k]);
int kToJ = parseInt(adj.get(k)[j]);
int infinity = Integer.MAX_VALUE;
if(iToK!=infinity && kToJ!=infinity && cur>iToK+kToJ)
adj.get(i)[j] = Integer.toString(iToK+kToJ);
if(parseInt(adj.get(i)[j])==infinity)
adj.get(i)[j]="INF";
}
}
}
for(int i=0;i<n;++i){
for(int j=0;j<n;++j){
sb.append(adj.get(i)[j]+" ");
}
sb.append("\n");
}
}
sc.close();
System.out.println(sb);
}
}
Second Approach (passed all test cases successfully):
/*package whatever //do not write package name here */
import java.util.*;
import java.lang.*;
import java.io.*;
class GFG {
public static void main (String[] args) {
Scanner sc = new Scanner(System.in);
StringBuffer sb = new StringBuffer();
int t = sc.nextInt();
while(t-->0){
int n = sc.nextInt();
int[][] adj = new int[n][n];
for(int i=0;i<n;++i)
for(int j=0;j<n;++j)
adj[i][j] = sc.nextInt();
for(int k=0;k<n;++k){
for(int i=0;i<n;++i){
for(int j=0;j<n;++j){
adj[i][j] = Math.min(adj[i][j],adj[i][k]+adj[k][j]);
}
}
}
for(int i=0;i<n;++i){
for(int j=0;j<n;++j){
if(adj[i][j]==10000000)
sb.append("INF"+" ");
else
sb.append(adj[i][j]+" ");
}
sb.append("\n");
}
}
sc.close();
System.out.println(sb);
}
}
In short, each iteration of the first solution is much slower than each iteration of the second one. At each iteration, you do the following:
Integer.parseInt, which is pretty slow. You can check this answer: https://stackoverflow.com/a/22783022/12463032, to see that each parse takes about 60 ns, which is probably more than 10 times slower than all other operations in the loop. It should make sense: at the very least parseInt takes time linear on the length of the string. Moreover, the function is not trivial (at the very least, parseInt must check that the number is an integer).
Integer.toString, which again takes time linear of the length of the string. Moreover, it involves object (string) creation, and your time may increase because of memory processing (e.g. GC may not work that well in your settings, and don't forget about memory allocation).
On a higher level, you violate Item 50 from "Effective Java" (http://wavelino.coffeecup.com/pdf/EffectiveJava.pdf): Avoid strings when other types are more appropriate. You perform numerical computations on your data; therefore, you should store them as numbers.

Plus Multiply | December Long Challenge Division 2

The first line of the input contains a single integer T denoting the number of test cases. The description of T test cases follows.
The first line of each test case contains a single integer N.
The second line contains N space-separated integers A1,A2,…,AN.
Output
For each test case, print a single line containing one integer ― the desired number of pairs.
Example Input
2
3
2 4 2
3
0 2 3
Example Output
1
0
My solution looks like:
class Codechef {
public static void main (String[] args) throws java.lang.Exception {
ArrayList<Integer> resultList = new ArrayList<Integer>();
Scanner scanner = new Scanner(System.in);
int T;
T = scanner.nextInt();
for(int i = 0; i < T; i++) {
int N;
N = scanner.nextInt();
int A[] = new int[N];
for(int j = 0; j < N; j++) {
A[j] = scanner.nextInt();
}
quick_sort(A, 0, N-1);
int pos = 0, pairs = 0;
while(pos < A.length - 1) {
if(A[pos] == A[pos + 1]) {
pos += 2;
pairs += 1;
} else {
++pos;
}
}
resultList.add(pairs);
}
for(int pairCount : resultList) {
System.out.println(pairCount);
}
scanner.close();
}
}
It successfully runs the example test cases but fails on submission, My question is, if the input is something like 1 1 2 2 1, then what should be the answer, 3? as there are 2 pairs of 1, and 1 of 2's.
Also, what will be the suggested data structure to be used for this purpose, Java with primitive data types is taking too much longer to execute it with 40,000 input values. What's wrong with my solution
To answer your first question, I'd say yes that each pair of 1's would count separately so you'd get 3.
I think your code is failing since you're only counting touching pairs after you sort.
For example,
1 1 1, you find the first pair at index 0/1, but then advance pos += 2.This means you're missing the two other pairs of 1's.
Your solution seems to be O(nlogn) because of sorting but I can think of a O(n) solution.
int[] backing = new int [10];
for (int j = 0; j < N; j++) {
int x = scanner.nextInt();
backing[x]++;
}
//At this point, you have a backing array with the frequency of each integer
You'll want something similar to this to calculate the number of pairs. It's the frequency of each integer choose 2, since you want to choose each occurrence of a pair.
So for example if you know you have 5 1's, then you'll compute:
5!/(2!*3!) = 10

Algorithm failing only for one test cases at hackerrank

I tried to attempt hackerrank problem of https://www.hackerrank.com/challenges/poisonous-plants and come up with below algorithm. I require some help as my solution is failing only 2 test cases and they are large data set so difficult to debug. I am including link to test case
http://ideone.com/B2WWaH its giving 204 answer but correct answer as per brute force method is 16. In simple words problem is that given a non empty array of positive integers in each iteration array element which is greater than it's previous is removed. After how many iteration there will be no removal.
Problem
There are N plants in a garden. Each of these plants has been added with some amount of pesticide. After each day, if any plant has more pesticide than the plant at its left, being weaker than the left one, it dies. You are given the initial values of the pesticide in each plant. Print the number of days after which no plant dies, i.e. the time after which there are no plants with more pesticide content than the plant to their left.
Input Format
The input consists of an integer N. The next line consists of N integers describing the array P where P[i] denotes the amount of pesticide in plant i.
Constraints
1≤N≤100000
0≤P[i]≤109
Output Format
Output a single value equal to the number of days after which no plants die.
I have made some observation
(1) First plant will always survive as there is no plant on its left side.
(2) In last longest decreasing sub-sequence starting from first plant will survive.
(3) We just have to find out how many days it will take for plant between elements of these sub-sequence to die.
(4) Came up with algorithm to track plant on which day it dies.
import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;
public class No {
public static void main(String[] args) throws FileNotFoundException {
/* Enter your code here. Read input from STDIN. Print output to STDOUT. Your class should be named Solution. */
int a = 0 , no = 0 ;
Scanner scno = new Scanner(new File("D:\\no.txt"));
a = scno.nextInt();
int[] arr = new int[a];
int n[] = new int[a]; int n1 = 0;
for ( int i = 0 ; i < arr.length ; i++ )
{
arr[i] = scno.nextInt();
if ( 0 != i )
{
if ( arr[i] > arr[i-1] )
{
n[1] = arr[i];
no = Math.max(no, 1);
}
else if ( arr[i] > arr[a] )
{
for ( int j = no ; j >= 0 ; j-- )
{
if ( 0 == j )
{
n[++no] = arr[i];
break;
}
if ( arr[i] > n[j] )
{
n[j] = arr[i];
break;
}
}
}
else
{
a = i;
n1 = Math.max(n1, no);
no = 0;
Arrays.fill(n, 0);
}
}
else
{
a = i;
}
}
System.out.println(Math.max(n1, no));
}
}
First of all, you have to follow some steps to solve any problem. In this type of problem, you have to:
Read all the data first, this means an independent loop to read all the plant data.
You apply your evolution model if there is one. This is another independent loop.
The assumptions you have made are not sufficient. I do not know if it will be possible to get it in one shot, you will easily define those characteristics if you first write a solution that works. The solution that will work for sure is to iterate and kill plants. Iterate from the right and kill the plant that satisfies the dying condition. And repeat until one loop doesn't kill any plant. The number of those days is the nomber of loops you have made minus one (the last that did not kill any plant). ArrayList will make your life simple.
in short, your can declare your data array as
ArraList<int> arr = new ArraList(a)
fill it as (after reading the size a of the vector
for ( int i = 0 ; i < a ; i++ ) arr.add(scno.nextInt());
and use a subroutine like this to do the job (this is just an indication, I did not test it)
private static int numberDaysNoD(ArraList<int> arr){
int nDays = 0;
boolean haveKilled = true;
while(haveKilled){
haveKilled = false;
for(int i = arr.size()-1; i>0; i--){
if(arr.get(i)>arr.get(i-1)){
arr.remove(i);
haveKilled = true;
}
}
nDays++;
}
return nDays--
}
Second there is one thing missing in the statement of your problem. Does the pesticide level in plants evolves? What is the evolution model? Or simply there is no evolution and each day, we simply kill those that have more that their left neighbor (this automatically change the left neighbor if one dies) and wait for the next day to repeat?

creating 2 dimensional array from text file

I am trying to add values into a 2d array from a text file. I cannot figure out how to convert the input file to teacher's array format. The file contains a first line that goes into an array that represents vertices. That part works fine. Every line after the first line contains numbers for the adjacency matrix. These numbers are read in but for some reason the slots in the matrix are not being filled. I need to use those numbers to fill a double array that would be the same as using this statement:
int[][] edges = {
{0,1}, {0,2},
{1,0},{1,2},
{2,0},{2,1},{2,3},{2,4},{2,6},
{3,2},{3,4},{3,5},
{4,2},{4,3},
{5,3},{5,6},
{6,2},{6,5},{6,7},
{7,6}
I have to read input from a txt file. The names represent the names of the nodes or vertices in my graph. The numbers represent the positions of the vertices in an adjacency matrix. For example the first line represents row o which maps to node john, and it means that john is connected by an edge to node 1 and 2 which are peter and mary. The numbers should map the same way as the array creation above. Here is what the file looks like :
john;peter;mary;susan;george;debbie;tom;bill;
0 1 2
1 0 2
2 0 1 3 4 6
3 2 4 5
4 2 3
5 3 6
6 2 5 7
7 6
And here is my code :
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class TestSocialGraph {
public static void main(String args[]){
String verts;
int[][] edges;
int[] intPasser;
File input = new File("GraphInput.txt");
String[] names;
try {
Scanner reader = new Scanner(input);
verts = reader.next();
names = verts.split(";");
edges = new int[names.length][names.length];
while (reader.hasNextLine()){
int b = 0;
int count = 0;
String passer = reader.nextLine();
// System.out.println(passer);
String[] temp = passer.split(" ");
intPasser = new int[temp.length];
for(int i = 1; i< temp.length; i++){
System.out.println(temp[i]);
intPasser[b] = Integer.parseInt(temp[i]);
b++;
}
System.out.println(intPasser[0]);
for(int i = 0; i< intPasser.length; i++){
edges[count][intPasser[i]] = 1;
}
count++;
}
} catch (FileNotFoundException e) {
System.out.println("File not found. Please place appropriate file and restart program");
System.exit(1);
}
}
}
It looks like you're trying to make an adjacency matrix...
I.e. The first line in your file says
0 1 2
So, this would mean node 0 is connected to node 1 & node 2. It matches with what your teacher has given also:
{0,1}, {0,2},
So, in the final 2D array edges, it should be represented like so (1s in the indexes to which node 0 is connected to):
edges[0] = {0, 1, 1, 0, 0, 0, 0, 0};
Dici's response is absolutely correct in this matter - it's the count variable's location that is creating a problem. Place int count = 0; outside the while loop, and use readLine() instead of read(), and you should get an adjacency matrix representation of that data.
The only problem is that the teacher's representation & the one you're trying to produce here are different. So, consequently, the later logic which processes these inputs will also vary. One program will run with what your teacher has provided, but won't run with the matrices you've created.
---------------------------EDIT---------------------------
In response to the comment, IMO, you'll need to go through the file twice - first to get the number of edges (in this case 20), then to fill your edges array with the actual values.
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
public class TestSocialGraph {
public static void main(String args[]) {
int[][] edges;
File input = new File("GraphInput.txt");
try {
Scanner reader = new Scanner(input);
reader.nextLine();// Skips the first line (nameList)
int count = 0;
// Count the total number of 2 element arrays
while (reader.hasNextLine()) {
String passer = reader.nextLine();
count += passer.split(" ").length - 1;
}
reader.close();
edges = new int[count][];
int i = 0;
reader = new Scanner(input);
reader.nextLine();// Skips the first line (nameList)
while (reader.hasNextLine()) {
String passer = reader.nextLine();
String[] split = passer.split(" ");
for (int j = 1; j < split.length; j++) {
edges[i + j - 1] = new int[2];
edges[i + j - 1][0] = Integer.parseInt(split[0]);
edges[i + j - 1][1] = Integer.parseInt(split[j]);
}
i += split.length - 1;
}
reader.close();
print(edges);
} catch (FileNotFoundException e) {
System.out.println(e);
}
}
private static void print(int[][] e) {
for (int i = 0; i < e.length; i++) {
for (int j = 0; j < e[i].length; j++)
System.out.print(e[i][j] + " ");
System.out.println();
}
}
}
I hope the code isn't too obscure/unreadable.
There are a lot of things to correct in your code.
verts = reader.next(); should be verts = reader.nextLine();.
in your question edges is a 20 x 2 matrix whereas in your code it is a 8 x 8 square matrix. The number of edges in your file does not seem to depend of the number of names in the first line, so why instantiating the array of edges like this ?
variable b is useless, you can replace it with i in the loop
variable count is never incremented (or at least the incremented value is never used) since it is reinitialized at each turn of the loop. That is the reason why you never fill certain lines.
your two loops could be merged into a unic one, without using a temporary array
Where does you data come from? I would avoid writing/maintaining a parser yourself. This is a waste of time. Did you think about using JSON? Your data (in the Java-code version) looks exactly like that.
When you can turn your data into
{
"vertices" : ["john","peter","mary","susan","george","debbie","tom","bill"],
"edges" : [[0,1], [0,2], ...]
}
you can use a standard JSON parser to read into a document model and directly start using the data.
This is an example of how to work with JSON data:
http://www.mkyong.com/java/json-simple-example-read-and-write-json/

Categories

Resources