I am trying to find a comparable value that is common to all rows in a 2D array.
For that value, I'd like to find the minimal (> 0) number of repetitions that exist in all rows.
For example, when working with a 2D array of String:
{
{A, C, B},
{A, A, B},
{C, D, A}
}
The only value that exists in all rows is "A". The minimal number of appearances in a row is 1, so the answer would be 1 A.
Here is my code: I am trying to search each column in a row for duplicates (or triplets, etc.), determine the count for a given row and compare it to the other rows to determine the row with the lowest quantity. Also, maybe there is a more elegant approach? For some reason it is not working (Collections is a 2d String array):
public class CommonElements {
ArrayList<String> commonCollections = new ArrayList<String>();
private int comparisons = 0;
int i, j, k;
int count, lowestCount;
String previousString = "";
int row[];
String current;
public Comparable[] findCommonElements(Comparable[][] collections) {
Arrays.sort(collections[0]);
row = new int[collections[0].length];
for (i = 0; i < collections[0].length; i++) { // first row column selection
current = collections[0][i].toString();
lowestCount = 1;
for (j = 0; j < collections.length; j++) { // row
count = 0;
for (k = 0; k < collections[0].length; k++) { // column
if (current.equals(collections[j][k].toString())) { // if contains same string as first row column selected
count++;
System.out.print(count + "\n");
}
}
if (lowestCount < count) {
lowestCount = count;
}
}
}
System.out.print(lowestCount);
return collections[0];
}
public int getComparisons() {
return comparisons;
}
}
Well, first you take collections[0][i].toString() when i is 0 so that evaluates to A, then program goes through all those loops and lowestCount is set to 1. Then your first for loop moves on to B and lowestCount is reseted without it being saved anywhere. You should save your lowestCount perhaps in array or a list, and at the end of the first for loop (after 2 other for loops) add the lowestCount to that array and you will have the lowest count of every letter. If you don't want to save it you can just System.out.println("Lowest count of letter: "+current+" is: "+lowestCount);. If you want to determine the row with the lowest count you can also save it in array (row with lowest count for every letter) and set it in that if that if statement passes (if(lowestCount < count)).
I'm not sure if I understood you correctly, but there is definitely a better approach to solving this problem.
You can do like this
int[][] arr = new int[5][2];
int count =0;
for(int[] i : arr){
count = count + i.length;
}
System.out.println(count);
Related
So, I am trying to create 2 randomly generated arrays,(a, and b, each with 10 unique whole numbers from 0 to 20), and then creating 2 arrays with the info of the last two. One containing the numbers that appear in both a and b, and another with the numbers that are unique to a and to b. The arrays must be listed in a "a -> [1, 2, 3,...]" format. At the moment I only know how to generate the 2 arrays, and am currently at the Intersection part. The problem is, that I can create a array with the correct list of numbers, but it will have the same length of the other two, and the spaces where it shouldn't have anything, it will be filled with 0s when its supposed to create a smaller array with only the right numbers.
package tps.tp1.pack2Arrays;
public class P02ArraysExtractUniqsAndReps {
public static void main(String[] args) {
int nbr = 10;
int min = 0;
int max = 20;
generateArray(nbr, min, max);
System.out.println();
}
public static int[] generateArray(int nbr, int min, int max) {
int[] a = new int[nbr];
int[] b = new int[nbr];
int[] s = new int[nbr];
s[0] = 0;
for (int i = 0; i < a.length; i++) {
a[i] = (int) (Math.random() * (max - min));
b[i] = (int) (Math.random() * (max - min));
for (int j = 0; j < i; j++) {
if (a[i] == a[j]) {
i--;
}
if (b[i] == b[j]) {
i--;
}
}
}
System.out.println("a - > " + Arrays.toString(a));
System.out.println("b - > " + Arrays.toString(b));
for (int k = 0; k < a.length; k++) {
for (int l = 0; l < b.length; l++) {
if (a[k] == b[l]) {
s[l] = b[l];
}else {
}
}
}
System.out.println("(a ∪ (b/(a ∩ b)) - > " + Arrays.toString(s));
return null;
}
public static boolean hasValue(int[] array, int value) {
for (int i = 0; i < array.length; i++) {
if (array[i] == value) {
return true;
}
}
return false;
}
}
Is there any way to create the array without the incorrect 0s? (I say incorrect because it is possible to have 0 in both a and b).
Any help/clarification is appreciated.
First, allocate an array large enough to hold the intersection. It needs to be no bigger that the smaller of the source arrays.
When you add a value to the intersection array, always add it starting at the beginning of the array. Use a counter to update the next position. This also allows the value 0 to be a valid value.
Then when finished. use Array.copyOf() to copy only the first part of the array to itself, thus removing the empty (unfilled 0 value) spaces. This works as follow assuming count is the index you have been using to add to the array: Assume count = 3
int[] inter = {1,2,3,0,0,0,0};
inter = Arrays.copyOf(inter, count);
System.out.println(Arrays.toString(inter);
prints
[1,2,3]
Here is an approach using a List
int[] b = {4,3,1,2,5,0,2};
int [] a = {3,5,2,3,7,8,2,0,9,10};
Add one of the arrays to the list.
List<Integer> list = new ArrayList<>();
for(int i : a) {
list.add(i);
}
Allocate the intersection array with count used as the next location. It doesn't matter which array's length you use.
int count = 0;
int [] intersection = new int[a.length];
Now simply iterate thru the other array.
if the list contains the value, add it to the intersection array.
then remove it from the list and increment count. NOTE - The removed value must be converted to an Integer object, otherwise, if a simple int value, it would be interpreted as an index and the value at that index would be removed and not the actual value itself (or an Exception might be thrown).
once finished the intersection array will have the values and probably unseen zeroes at the end.
for(int i = 0; i < b.length; i++) {
int val = b[i];
if (list.contains(val)) {
intersection[count++] = val;
list.remove(Integer.valueOf(val));
}
}
To shorten the array, use the copy method mentioned above.
intersection = Arrays.copyOf(intersection, count);
System.out.println(Arrays.toString(intersection));
prints
[3, 2, 5, 0, 2]
Note that it does not matter which array is which. If you reverse the arrays for a and b above, the same intersection will result, albeit in a different order.
The first thing I notice is that you are declaring your intersection array at the top of the method.
int[] s = new int[nbr];
You are declaring the same amount of space for the array regardless of the amount you actually use.
Method Arrays.toString(int []) will print any uninitialized slots in the array as "0"
There are several different approaches you can take here:
You can delay initializing the array until you have determined the size of the set you are dealing with.
You can transfer your content into another well sized array after figuring out your result set.
You could forego using Array.toString, and build the string up yourself.
Hello all please check the problemHackerRank Problem Statement
This is my solution for the above problem(link)
static int migratoryBirds(List<Integer> arr) {
int ar[]=new int[arr.size()];
for(int i=0;i<arr.size();i++){
ar[i] = Collections.frequency(arr,arr.get(i));
// ar[i] = obj.occuranceOfElement(arr,arr.get(i));
}
int maxAt = 0;
for (int i = 0; i < ar.length; i++) {
maxAt = ar[i] > ar[maxAt] ? i : maxAt;
}
return arr.get(maxAt);
}
my code is unable to handle when the array size is bigger,example 17623 elements in array.
Terminated due to timeout
The problem is in the second for loop which iterates over the array and gives me the index of the largest number in the array.Is there any other way that I could increase the performance.
Your problem is in this part:
for(int i = 0; i < arr.size(); i++)
ar[i] = Collections.frequency(arr, arr.get(i));
This is O(N²): Collections.frequency() iterates over whole list to calculate frequency for only one element. Manually, you can iterate over the list to calculate frequencey for all elements.
Moreover, ther're only 5 birds, so you need only 5 length array.
static int migratoryBirds(int[] arr) {
int max = 1;
int[] freq = new int[6];
for (int val : arr)
freq[val]++;
for (int i = 2; i < freq.length; i++)
max = freq[i] > freq[max] ? i : max;
return max;
}
Your problem is the call to Colletions.frequency, which is an O(N) operation. When you call it from inside a loop it becomes O(N²) and that consumes all your time.
Also, are you sure which implmentation of List you receive? You call list.get(i) which might also be O(N) if the implementation is a LinkedList.
The target of this exercise is to calculate the frequency of each value in one pass over the input. You need a place where you store and increase the number of occurrences for each value and you need to store the largest value of the input.
You have also skipped over a crucial part of the specification. The input has limits which makes solving the problem easier than you now think.
Here's another one:
static int migratoryBirds(List<Integer> arr) {
int freq[]=new int[6];
for(int i=0;i<arr.size();i++){
++freq[arr.get(i)];
}
int maxAt = 1;
for (int i = 2; i < freq.length; i++) {
if (freq[i] > freq[maxAt]) {
maxAt = i;
}
}
return maxAt;
}
We can determine the type number of the most common bird in one loop. This has the time complexity O(n).
static int migratoryBirds(int[] arr) {
int highestFrequency = 0;
int highestFrequencyBirdType = 0;
int[] frequencies = new int[5]; // there are 5 bird types
for (int birdType : arr) {
int frequency = ++frequencies[birdType - 1];
if (frequency > highestFrequency) {
highestFrequency = frequency;
highestFrequencyBirdType = birdType;
} else if (frequency == highestFrequency && birdType < highestFrequencyBirdType) {
highestFrequencyBirdType = birdType;
}
}
return highestFrequencyBirdType;
}
For each element in the array arr we update the overall highestFrequency and are storing the corresponding value representing the highestFrequencyBirdType . If two different bird types have the highest frequency the lower type (with the smallest ID number) is set.
I came across below problem related to Matrix Manipulation.
problem statement
There is a NxN matrix,divided into N * N cells. Each cell has a predefined value. Which would be given as an input. Iteration has to happen K number of times which is also given in the test input. We have to make sure that we pick the optimum/min value of rows/columns at each iteration. Final output is the cumulative sum of optimum value saved at the end of each iteration.
Steps 1. Sum up the individual row and column and find the min sum of rows and columns, (it could be a row or a column, just need the minimum row or a column)
Step 2. Store the sum found above separately
Step 3.
Increment elements of the min. sum row or column. by 1
Repeat steps 1,2,3 from 1 to Kth value
add the sum at each iteration(specified in step2)
output is the sum obtained on on the Kth iteration.
Sample data
2 4
1 3
2 4
Output data
22
I was able to write a code (in java) and tested the same for some sample test cases. The output worked fine. The code works fine for sample data matrix of lower order, say, 2x2,4x4,even till 44x40 (that has less iteration). However, when the matrix size is increased to 100X100 (complex iteration), I see the expected output output values differ at 10s and hundreds place of the digit from the actual output and its random. Since I am not able to find a correct pattern of output vs input. Now, it is taking a toll on me to really debugging 500th loop to identify the issue. Is there any better way or approach to solve such problem related to huge matrix manipulation. Has anyone come across issues similar to this and solved it.
I am mainly interested in knowing the correct approach to solve given matrix problem. What Data structure to use in java. At present, I am using primitive DS and arrays int[] or long[] to solve this problem. Appreciate any help in this regard.
Which data structure?
What you need here is a data structure which allows you to efficiently query and update the minimum sum line. The most commonly used for this is a heap https://en.wikipedia.org/wiki/Heap_(data_structure).
For your purposes it's probably best to just implement the simplest kind, an array-based binary heap:
See here: https://en.wikipedia.org/wiki/Binary_heap
And here: http://courses.cs.washington.edu/courses/cse373/11wi/homework/5/BinaryHeap.java
..for implementation details.
Procedure:
Initialize your heap to size M + N where M, N are the number of rows and columns.
Before the loop, pre-compute the sum of each row and column, and add them as objects to the heap. Also add two arrays A, B which store the row and columon objects separately.
Now heapify the heap array with respect to the line sum attribute. This ensures the heap follows the criterion of the binary heap structure (parent always > children). Read the sources to find out more about how to implement this (quite easy for a fixed array)
For each iteration, look at the first element in the heap array. This is always the one with the smallest line sum. If this is a row object, then increment the sum attribute by N (no. of columns), and increment each object in B (list of columns) by 1. Do the same if it's a column.
After this, always heapify before the next iteration.
At the end, just return the first element's attribute.
Time complexity:
The original naive solution (looping through all columns and rows every time) is .
Using a heap, the heapify operation at each step is (for a binary heap).
This means the total complexity is , FAR smaller. The max term is to compensate for the fact that at each iteration it may be either rows or columns which are incremented.
As a side note, there are other heap structure types which have even better time complexity than the binary heap, e.g. binomial trees, Fibonacci heaps etc. These however are far more complicated, and have higher constant-factor overheads as a result. Thus for your project I feel they are not necessary, as many of them need phenomenal data set sizes to justify for the constant factor overhead.
Besides, they all support the same external operations as the binary heap, as defined by the Abstract Data Structure of Heap.
(heapify is an internal operation specific to the binary heap structure. Quite a few of the other ones are theoretically superior as they do this operation implicitly and "lazily")
O(KN + N*N) Solution:
You can just work with sum of columns and rows, and not store or manipulate them directly.
First sum all the columns and rows, in a 2*N array, first row being sum of columns, a[0][0] is sum of first column, a[0][1] is sum of second column, and second row is sum of rows, a[1][0] sum of first row, etc...
Then do the following for iterating:
Find min in array a .
Add it to the answer.
Add N to the min of row or column selected.
If the min is row add one to all cols and if it is a column add one to all rows.
If needed any further explanation, don't hesitate to comment.
I am doing like this for solving the above problem...
void matrixManipulation() throws IOException {
int N = Reader.nextInt();
int[][] matrix = new int[N][N];
int K = Reader.nextInt();
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
matrix[i][j] = Reader.nextInt();
}
}
// System.out.println("********Inital position**********");
// for (int i = 0; i < N; i++) {
// for (int j = 0; j < N; j++) {
// System.out.print(matrix[i][j]);
// }
// System.out.println();
// }
// System.out.println("********Inital position**********");
CalculateSum calculateSum = new CalculateSum();
int[] row = new int[N];
int[] row_clone = new int[N];
int[] col = new int[N];
int[] col_clone = new int[N];
int test =0;
for (int kk = 0; kk < K; kk++) {
row = calculateSum.calculateRowSum(matrix, N);
row_clone = row.clone();
/* just sort it either Arrarys sort or any other ---starts here*/
// for (int i = 1; i < row.length; i++) {
// row_orignial[i] = row[i];
// }
// Arrays.sort(row);
Node root1 = insert(null, row[0], 0, row.length);
for (int i = 1; i < row.length; i++) {
insert(root1, row[i], 0, row.length);
}
sortArrayInOrderTrvsl(root1, row, 0);
/* just sort it either Arrarys sort or any other ---ends here*/
col = calculateSum.calculateColumnSum(matrix, N);
col_clone = col.clone();
/* just sort it either Arrarys sort or any other ---starts here*/
// for (int i = 1; i < col.length; i++) {
// col_orignial[i] = col[i];
// }
// Arrays.sort(col);
Node root2 = insert(null, col[0], 0, col.length);
for (int i = 1; i < row.length; i++) {
insert(root2, col[i], 0, col.length);
}
sortArrayInOrderTrvsl(root2, col, 0);
/* just sort it either Arrary.sort or any other---ends here */
int pick = 0;
boolean rowflag = false;
int rowNumber = 0;
int colNumber = 0;
if (row[0] < col[0]) {
pick = row[0];// value
rowflag = true;
for (int i = 0; i < N; i++) {
if (pick == row_clone[i])
rowNumber = i;
}
} else if (row[0] > col[0]) {
pick = col[0];// value
rowflag = false;
for (int i = 0; i < N; i++) {
if (pick == col_clone[i])
colNumber = i;
}
} else if(row[0] == col[0]){
pick = col[0];
rowflag = false;
for (int i = 0; i < N; i++) {
if (pick == col_clone[i])
colNumber = i;
}
}
test= test + pick;
if (rowflag) {
matrix = rowUpdate(matrix, N, rowNumber);
} else {
matrix = columnUpdate(matrix, N, colNumber);
}
System.out.println(test);
// System.out.println("********Update Count"+kk+" position**********");
// for (int i = 0; i < N; i++) {
// for (int j = 0; j < N; j++) {
// System.out.print(matrix[i][j]);
// }System.out.println();
// }
// System.out.println("********Update Count"+kk+" position**********");
}
// System.out.println("********Final position**********");
// for (int i = 0; i < N; i++) {
// for (int j = 0; j < N; j++) {
// System.out.print(matrix[i][j]);
// }System.out.println();
// }
// System.out.println("********Final position**********");
// System.out.println(test);
}
I have made a program that outputs the number of repeats in a 2D array. The problem is that it outputs the same number twice.
For example: I input the numbers in the 2D array through Scanner: 10 10 9 28 29 9 1 28.
The output I get is:
Number 10 repeats 2 times.
Number 10 repeats 2 times.
Number 9 repeats 2 times.
Number 28 repeats 2 times.
Number 29 repeats 1 times.
Number 9 repeats 2 times.
Number 1 repeats 1 times.
Number 28 repeats 2 times.
I want it so it skips the number if it has already found the number of repeats for it. The output should be:
Number 10 repeats 2 times.
Number 9 repeats 2 times.
Number 28 repeats 2 times.
Number 29 repeats 1 times.
Number 1 repeats 1 times.
Here is my code:
import java.util.Scanner;
public class Repeat
{
static Scanner leopard = new Scanner(System.in);
public static void main(String [] args)
{
final int ROW = 10; //Row size
final int COL = 10; //Column size
int [][] num = new int[ROW][COL];
int size;
//Get input
size = getData(num);
//Find repeat
findRepeats(num, size);
}
public static int getData(int [][] num)
{
int input = 0, actualSize = 0; //Hold input and actualSize of array
System.out.print("Enter positive integers (-999 to stop): ");
//Ask for input
for(int i = 0; i < num.length && input != -999; i++)
{
for(int j = 0; j < num[i].length && input != -999; j++)
{
input = leopard.nextInt();
//Check if end
if(input != -999)
{
num[i][j] = input;
actualSize++;
}
}
}
System.out.println();
return actualSize;
}
public static void findRepeats(int [][] num, int size)
{
int findNum;
int total = 0, row = 0, col = 0;
for(int x = 0; x < size; x++)
{
//Set to number
findNum = num[row][col];
//Loop through whole array to find repeats
for(int i = 0; i < num.length; i++)
{
for(int j = 0; j < num[i].length; j++)
{
if(num[i][j] == findNum)
total++;
}
}
//Cycle array to set next number
if(col < num[0].length-1)
col++;
else
{
row++; //Go to next row if no more columns
col = 0; //Reset column number
}
//Display total repeats
System.out.println("Number " + findNum + " appears " + total + " times.");
total = 0;
}
}
}
I know why it is doing it, but I cannot figure out how to check if the number has already been checked for it to skip that number and go to the next number. I cannot use any classes or code that is not used in the code.
Since you cannot use anything other than this, lets say, basic elements of Java consider this:
Make another temporary 2D array with two columns (or just two separate arrays, personally I prefer this one). On the start of the algorithm the new arrays are empty.
When you take a number (any number) from the source 2D structure, first check if it is present in the first temporary array. If it is, just increment the value (count) in the second temporary array for one (+1). If it is not present in the first tmp array, add it to it and increase the count (+1) in the second at the same index as the newly added number in the first (which should be the last item of the array, basically).
This way you are building pairs of numbers in two arrays. The first array holds all your distinct values found in the 2D array, and the second one the number of appearances of the respective number from the first.
At the and of the algorithm just iterate the both arrays in parallel and you should have your school task finished. I could (and anyone) code this out but we are not really doing you a favor since this is a very typical school assignment.
It's counting the number two times, first time it appears in the code and second time when it appears in the code.
To avoid that keep a system to check if you have already checked for that number. I see you use check int array but you haven't used it anywhere in the code.
Do this,
Put the number in the check list if you have already found the count of it.
int count = 0;
check[count] = findNum;
count++;
Note: You can prefill you array with negative numbers at first in order to avoid for having numbers that user already gave you in input.
Next time in your for loop skip checking that number which you have already found a count for
for(int x = 0; x < size; x++) {
findNum = num[row][col];
if(check.containsNumber(findNUm)) { //sorry there is no such thing as contains for array, write another function here which checks if a number exists in the array
//skip the your code till the end of the first for loop, or in other words then don't run the code inside the for loop at all.
}
}
Frankly speaking I think you have just started to learn coding. Good luck! with that but this code can be improved a lot better. A piece of advice never create a situation where you have to use 3 nested for loops.
I hope that you understood my solution and you know how to do it.
All answers gives you some insight about the problem. I try to stick to your code, and add a little trick of swap. With this code you don't need to check if the number is already outputted or not. I appreciate your comments, structured approach of coding, and ask a question as clear as possible.
public static void findRepeats(int [][] num, int size)
{
int findNum;
int total = 1, row = 0, col = 0;
int [] check = new int[size];
while(row < num.length && col < num[0].length)
{
//Set to number
findNum = num[row][col];
//Cycle array to set next number
if(col < num[0].length-1)
col++;
else
{
row++; //Go to next row if no more columns
col = 0; //Reset column number
}
//Loop through whole array to find repeats
for(int i = row; i < num.length; i++)
{
for(int j = col; j < num[i].length; j++)
{
if(num[i][j] == findNum) {
total++;
//Cycle array to set next number
if(col < num[0].length-1)
col++;
else
{
row++; //Go to next row if no more columns
col = 0; //Reset column number
}
if(row < num.length - 1 && col < num[0].length -1)
num[i][j] = num[row][col];
}
}
}
//Display total repeats
System.out.println("Number " + findNum + " appears " + total + " times.");
total = 1;
}
}
you can use a HashMap to store the result. It Goes like this:
// Create a hash map
HashMap arrayRepeat = new HashMap();
// Put elements to the map
arrayRepeat.put(Number, Repeated);
Guys, I am struggling studying for exam with the 2d array of past exam paper. I have to write a method
sumr static (int[][] v)
that returns a 2d array consisting of 2 rows and the entries of the first row sums of v and the second row is the same of the first row of v. Eg:
a = {{2,3,3}, {1,3}, {1,2}}
the method returns 2d array
b = {{8,4,3},{2,3,3}}
I first try to make my method return a 2d array, but I was having the error illegal start of expression, now I have the following code, but the last element does not print and the elements a printed all in in line, not in a matrix way... Please guys help me, my exam is tomorrow.
public class Sum
{
// int[][] a = {{2, 3, 3}, {1, 3}, {1, 2}};
public void sumr(int[][] v)
{
for(int rows = 0; rows < v.length; rows++){
for(int columns = 0; columns < v.length; columns++){
int result = v[rows][columns];
System.out.print(result + " ");
//return [][] result;
}
}
}
public int getCount(int[][] Array)
{
int result = 0; //temp location to store current count
for (int i = 0;i <= Array.length -1;i++){//loop around first array
//get the length of all the arrays in the first array
//and add them onto the temp variable
result += Array[i].length;
}
return result;
}
}
In the outer loop (after the inner loop) include:
System.out.println(); // go to next line!
And check against the inner-array length!!
int[] innerArray = v[rows];
for(int columns = 0; columns < innerArray.length; columns++){
It is:
public void sumr(int[][] v)
{
for(int rows = 0; rows < v.length; rows++){
int[] innerArray = v[rows];
for(int columns = 0; columns < innerArray.length; columns++){
int result = v[rows][columns];
System.out.print(result + " ");
//return [][] result;
}
System.out.println(); // go to next line!
}
}
Once you can iterate:
You must construct a two-items array:
1st item: "summed array"
2nd item: the same as v[0]
You must build that result.
You must build the 1st item iterating over v. Like you are trying to do. For each row (outer loop) you will iterate over the row and sum its values. So after processing each row (after the inner loop) you will have the summed value. That value must be placed into the "summed array".
Next you can build directly the result array, assigning the built sum to its first place and v[0] to the second place.
But I'm not writing code yet to let you do it ;-)