Finding all possible combinations of elements of six arrays - java

I have 6 arrays, each has 8 elements. I'd like to write a method that reveals all the possible combinations of all the elements of all arrays like:
firstArray firstElement, secondArray firstElement,.... sixthArray firstElement
firstArray secondElement, secondArray firstElement,.... sixthArray firstElement
....etc...
firstArray lastElement, secondArray lastElement,.... sixthArray lastElement
How can I do this in the most efficient way, the most performance-friendly way?
for (int i = 0; i < A.length; i++) {
for (int j = 0; j < B.length; j++) {
for (int h = 0; h < C.length; h++) {
for (int k = 0; k < D.length; k++) {
for (int l = 0; l < E.length; l++) {
for (int n = 0; n < F.length; n++) {
System.out.println(A[i] + " "
+ B[j] + " "
+ C[h] + " "
+ D[k] + " "
+ E[l] + " "
+ F[n]);
}
}
}
}
}
}

Simplest Code would be:
for (first array a) {
for (second array b) {
for (third array c) {
for (fourth array d) {
for (fifth array e) {
for (sixth array f) {
System.out.println(a[], b[], c[], d[], e[], f[]);
}
}
}
}
}
}
This is not good performance wise as it will take - no. of arrays * element per array * element per array time.

This is fast becoming an SO FAQ, but for the life of me I can't find the right question that this is a duplicate of, so here's the FPA (frequently provided answer).
Generate all the 6-digit base-8 numbers from 000000 to 777777 in turn. Each number specifies one of the sets you are looking for: the first digit identifies the element of the first array, the second digit the element of the second array, etc.
That should be enough to get you started, any 'help' I provided in Java would be laughed at. Whether this is better than the answer you already have (or indeed, materially different from it), I leave you and others to judge.
For your future reference you are trying to compute the cartesian product of your 6 arrays. As to the efficiency of these approaches, well computing the cartesian product of 2 sets each of n elements is O(n^2) and there is no getting around that by clever programming. So for 6 sets, each of n elements, the computational complexity is going to be O(n^6).

Related

Creating a method that merges 2 arrays into one sorted array in ascending order in Java

For part of an assignment, I have to create a method that merges 2 arrays into one sorted array in ascending order. I have most of it done, but I am getting a bug that replaces the last element in the array with 0. Has anyone ever run into this problem and know a solution? Heres my code:
public static OrderedArray merge(OrderedArray src1, OrderedArray src2) {
int numLength1 = src1.array.length;
int numLength2 = src2.array.length;
//combined array lengths
int myLength = (numLength1 + numLength2);
// System.out.println(myLength);
OrderedArray mergedArr = new OrderedArray(myLength);
//new array
long[] merged = new long[myLength];
//loop to sort array
int i = 0;
int j = 0;
int k = 0;
while (k < src1.array.length + src2.array.length - 1) {
if(src1.array[i] < src2.array[j]) {
merged[k] = src1.array[i];
i++;
}
else {
merged[k] = src2.array[j];
j++;
}
k++;
}
//loop to print result
for(int x = 0; x < myLength; x++) {
System.out.println(merged[x]);
}
return mergedArr;
}
public static void main(String[] args) {
int maxSize = 100; // array size
// OrderedArray arr; // reference to array
OrderedArray src1 = new OrderedArray(4);
OrderedArray src2 = new OrderedArray(5);
// arr = new OrderedArray(maxSize); // create the array
src1.insert(1); //insert src1
src1.insert(17);
src1.insert(42);
src1.insert(55);
src2.insert(8); //insert src2
src2.insert(13);
src2.insert(21);
src2.insert(32);
src2.insert(69);
OrderedArray myArray = merge(src1, src2);
This is my expected output:
1
8
13
17
21
32
42
55
69
and this is my current output:
1
8
13
17
21
32
42
55
0
While merging two arrays you are comparing them, sorting and merging but what if the length of two arrays is different like Array1{1,3,8} and Array2{4,5,9,10,11}. Here we will compare both arrays and move the pointer ahead, but when the pointer comes at 8 in array1 and at 9 in array2, now we cannot compare ahead, so we will add the remaining sorted array;
Solution:-
(Add this code between loop to sort array and loop to print array)
while (i < numLength1) {
merged[k] = src1.array[i];
i++;
k++;
}
while (j < numLength2) {
merged[k] = src2.array[j];
j++;
k++;
}
To answer your main question, the length of your target array is src1.array.length + src2.array.length, so your loop condition should be one of:
while (k < src1.array.length + src2.array.length) {
while (k <= src1.array.length + src2.array.length - 1) {
Otherwise, you will never set a value for the last element, where k == src1.array.length + src2.array.length - 1.
But depending on how comprehensively you test the code, you may then find you have a bigger problem: ArrayIndexOutOfBoundsException. Before trying to use any array index, such as src1.array[i], you need to be sure it is valid. This condition:
if(src1.array[i] < src2.array[j]) {
does not verify that i is a valid index of src1.array or that j is a valid index of src2.array. When one array has been fully consumed, checking this condition will cause your program to fail. You can see this with input arrays like { 1, 2 } & { 1 }.
This revision of the code does the proper bounds checks:
if (i >= src1.array.length) {
// src1 is fully consumed
merged[k] = src2.array[j];
j++;
} else if (j >= src2.array.length || src1.array[i] < src2.array[j]) {
// src2 is fully consumed OR src1's next is less than src2's next
merged[k] = src1.array[i];
i++;
} else {
merged[k] = src2.array[j];
j++;
}
Note that we do not need to check j in the first condition because i >= src1.array.length implies that j is a safe value, due to your loop's condition and the math of how you are incrementing those variables:
k == i + j due to parity between k's incrementing and i & j's mutually exclusive incrementing
k < src1.array.length + src2.array.length due to the loop condition
Therefore i + j < src1.array.length + src2.array.length
If both i >= src1.array.length and j >= src2.array.length then i + j >= src1.array.length + src2.array.length, violating the facts above.
A couple other points and things to think about:
Be consistent with how you refer to data. If you have variables, use them. Either use numLength1 & numLength2 or use src1.length & src2.length. Either use myLength or use src1.array.length + src2.array.length.
Should a merge method really output its own results, or should the code that called the method (main) handle all the input & output?
Is the OrderedArray class safe to trust as "ordered", and is it doing its job properly, if you can directly access its internal data like src1.array and make modifications to the array?
The best way to merge two arrays without repetitive items in sorted order is that insert both of them into treeSet just like the following:
public static int[] merge(int[] src1, int[] src2) {
TreeSet<Integer> mergedArray= new TreeSet<>();
for (int i = 0; i < src1.length; i++) {
mergedArray.add(src1[i]);
}
for (int i = 0; i < src2.length; i++) {
mergedArray.add(src2[i]);
}
return mergedArray.stream().mapToInt(e->(int)e).toArray();
}
public static void main(String[] argh) {
int[] src1 = {1,17,42,55};
int[] src2 = {8,13,21,32,69};
Arrays.stream(merge(src1,src2)).forEach(s-> System.out.println(s));
}
output:
1
8
13
17
21
32
42
55
69

Significant Running time difference between two algorithms solving same task

In the process of learning algorithms, I have written code to compare 2 algorithms performance in terms of running time. The task of these algorithms is to find all the pairs of numbers in an array that add up to a specific number.
First approach - Brute force.
2 for loops to find the pairs of numbers that add up to the given number. Basically time complexity is O(n*n).
Second approach - Efficient
First sort the array, then have start and end as index to the beginning and end of array, and depending on the sum of these elements in the positions, move left or right to find pairs of numbers.
My question is -
I am printing the running time of each algorithm approach. But it seems like the running time of the Brute force approach is faster than the Efficient one. Why is this happening?
See the code here -
public class MainRunner {
final private static int numberRange = 100000;
public static void generateRandomNumbers(int[] array, int[] dupArray) {
System.out.println("Generated Array: ");
Random random = new Random();
for (int i = 0; i < array.length; i++) {
int generatedRandomInt = random.nextInt(array.length) + 1;
array[i] = dupArray[i] = generatedRandomInt;
}
}
public static void main(String[] args) {
int[] array = new int[numberRange];
int[] dupArray = new int[numberRange];
generateRandomNumbers(array, dupArray);
Random random = new Random();
int sumToFind = random.nextInt(numberRange) + 1;
System.out.println("\n\nSum to find: " + sumToFind);
// Starting Sort and Find Pairs
final long startTimeSortAndFindPairs = System.currentTimeMillis();
new SortAndFindPairs().sortAndFindPairsOfNumbers(sumToFind, array);
final long durationSortAndFind = System.currentTimeMillis() - startTimeSortAndFindPairs;
// Starting Find Pairs
final long startTimeFindPairs = System.currentTimeMillis();
new FindPairs().findPairs(sumToFind, dupArray);
final long durationFindPairs = System.currentTimeMillis() - startTimeFindPairs;
System.out.println("Sort and Find Pairs: " + durationSortAndFind);
System.out.println("Find Pairs: " + durationFindPairs);
}
}
SortAndFindPairs.java
public class SortAndFindPairs {
public void sortAndFindPairsOfNumbers(int argNumberToFind, int[] array) {
Arrays.sort(array);
System.out.println("\n\nResults of Sort and Find Pairs: \n");
int startIndex = 0;
int endIndex = array.length - 1;
while (startIndex < endIndex) {
int sum = array[startIndex] + array[endIndex];
if (argNumberToFind == sum) {
//System.out.println(array[startIndex] + ", " + array[endIndex]);
startIndex++;
endIndex--;
} else if (argNumberToFind > sum) {
startIndex++;
} else {
endIndex--;
}
}
}
And the FindPairs.java
public class FindPairs {
public void findPairs(int argNumberToFind, int[] array) {
System.out.println("\nResults of Find Pairs: \n");
int randomInt1 = 0;
int randomInt2 = 0;
for (int i = 0; i < array.length - 1; i++) {
for (int j = i + 1; j < array.length; j++) {
int sum = array[i] + array[j];
if (argNumberToFind == sum) {
//System.out.println(array[i] + ", " + array[j]);
//randomInt1++;
//randomInt2--;
}
}
}
}}
Only on adding the two variables randomInt1 and randomInt2 in the FindPairs.java, the running time difference is seen. Or else, the running time of FindPairs.java is much less than SortAndFindPairs.java. So why does adding just 2 variable operations increase time by so much? According to conventions, simple operations should consume negligible time. Am I missing out something here?
Results for numberRange = 1000000
Results of Find Pairs:
Sort and Find Pairs: 641
Find Pairs: 57
I think the problem is your compiler optimization playing tricks to you. I tried different permutations of your code, and noticed that the double for loop in FindPairs is doing almost nothing. So the compiler may be stripping some of the code.
I got this numbers with the exact copy of your code:
Sort and Find Pairs: 43
Find Pairs: 13
Consistently (I ran it several times to double check) Sort and find was slower, everytime.
But then I changed the inner loop for to do nothing:
for (int j = i + 1; j < array.length; j++) {
//int sum = array[i] + array[j];
//if (argNumberToFind == sum) {
//System.out.println(array[i] + ", " + array[j]);
//randomInt1++;
//randomInt2--;
//}
And guess what? I got:
Sort and Find Pairs: 20
Find Pairs: 11
Tried several times and the numbers were pretty similar. By removing both loops the runtime for find pairs went to 1. So My guess, maybe the optimization step of the compiler is assuming that the code inside the inner loop doesn't have any effect and thus removes it. The code in Sort and find is a little smarter and so it gets kept.
Now, I tried a different thing, I commented out the increment of randomInt1, but left the sum and if commented,
for (int j = i + 1; j < array.length; j++) {
//int sum = array[i] + array[j];
//if (argNumberToFind == sum) {
//System.out.println(array[i] + ", " + array[j]);
randomInt1++;
//randomInt2--;
//}
and then I got:
Sort and Find Pairs: 42
Find Pairs: 5
Wow, suddenly it got faster! (maybe the compiler replaced the for for the arithmetic calculation of randomInt1 by using the loop bounds?)
My last attempt. You can noticed that this is not a fair comparison, the sort and find have a lot of logic involved, while the find doesn't. It actually does nothing when it find a pair. So to make it apples to apples we want to be sure find pairs actually do something, and lets make sure sort and find do the same extra amount (like adding the same number on both sides of the equation). So I changed the methods to calculate the count of matching pairs instead. Like this:
System.out.println("\nResults of Find Pairs: \n");
long randomInt1 = 0;
int randomInt2 = 0;
int count = 0;
for (int i = 0; i < array.length - 1; i++) {
for (int j = i + 1; j < array.length; j++) {
int sum = array[i] + array[j];
if (argNumberToFind == sum) {
count++;
}
}
}
System.out.println("\nPairs found: " + count + "\n");
and
public void sortAndFindPairsOfNumbers(int argNumberToFind, int[] array) {
Arrays.sort(array);
System.out.println("\n\nResults of Sort and Find Pairs: \n");
int startIndex = 0;
int endIndex = array.length - 1;
int count = 0;
while (startIndex < endIndex) {
int sum = array[startIndex] + array[endIndex];
if (argNumberToFind == sum) {
//System.out.println(array[startIndex] + ", " + array[endIndex]);
startIndex++;
endIndex--;
count++;
} else if (argNumberToFind > sum) {
startIndex++;
} else {
endIndex--;
}
}
System.out.println("\nPairs found: " + count + "\n");
}
And then got:
Sort and Find Pairs: 38
Find Pairs: 4405
The time for find pairs blowed up! And the sort and find kept in line with what we were seeing before.
So the most likely answer to your problem is that the compiler is optimizing something, and an almost empty for loop is something that the compiler can definitely use to optimize. whilst for the sort and find, the complex logic may cause the optimizer to step back. Your algorithm lessons are find. Here java is playing you a trick.
One more thing you can try is use different languages. I'm pretty sure you will find interesting stuff by doing so!
As stated by LIuxed, sort operation takes some time. If you invest time in sorting, why do you then not take advantage of the fact that list items are sorted?
If list elements are sorted, you could use a binary search algorithm... start in the middle of the array, and check if you go 1/2 up, or 1/2 down. As a result, you can get faster performance with sorted array for seeking a value. Such an algorithm is already implemented in the Arrays.binarySearch methods.
See https://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html#binarySearch(int[],%20int)
You will notice the difference when you sort just once, but seek many times.
Calling the Array.sort(MyArray) method, takes long time because it uses a selection algorithm; this means, the Sort method go through all the array x times ( x= array.lenght) searching for the smallest/biggest value, and set it on top of the array, and so on.
Thats why, using this method takes a long time, depending on the array size.
I removed everything from your sortAndFindPairsOfNumbers method, just kept
Arrays.sort(array);
But still time difference is much more.
This means most of the time taken is by sort method.
So your thinking that second approach is Efficient one is not correct. Its all about input size.
If you keep numberRange, lets say, 1000, then SortAndFindPairs will be faster.

How to search a 2D array inside a 2D array efficiently?

I am trying to search a 2D array inside a 2D array, and I have tried the following code to do so:
loopX: for (int x = 0; x < str1.length - str2.length + 1; ++x)
loopY: for (int y = 0; y < str1[x].length - str2[0].length + 1; ++y)
{
for (int xx = 0; xx < str2.length; ++xx)
for (int yy = 0; yy < str2[0].length; ++yy)
{
if (str1[x + xx][y + yy] != str2[xx][yy])
{
k++;
continue loopY;
}
}
// Found the submatrix!
System.out.println("Found at: " + x + " " + y);
break loopX;
}
System.out.println(k);
In this code str1 is the larger 2D array inside which I am trying to search and match the smaller 2D array str2. Both are char arrays.
k is the element I need to keep track of in case, there is no match.
I would also like to know what can be the most efficient way to do so.
For this the algorithm I thought, that first I should match only the starting element of both the arrays, and when they match then only go and match other elements.
But, I am not able to write specific code for this.
I would appreciate if someone could help me in this.

Find all triplets in array in O(n^2)

I am trying to print all triplets in array, unlike 3SUM or anything similiar, they don't satisfy any condition. I just want to print them all.
My simple solution
for (int i = 0; i < arr.length - 2; i++) {
for (int j = i + 1; j < arr.length - 1; j++) {
for (int k = j + 1; k < arr.length; k++){
System.out.println(arr[i] + " " + arr[j] + " " + arr[k]);
}
}
}
runs in O(n^3) with the amount of triplets being ((n)*(n-1)*(n-2))/(3!).
So my question is, can this be done any faster than O(n^3)?
n choose 3, which is the number of combinations of triplets, is
O(n^3).
So no, theoretically it is impossible to do better than that since the mere operation of printing them will take O(n^3) operations.
You can't print n^3 triplets less in n^3 operation.
If time of computing is problem you can divide your print operation in n threads so in theory that will reduce time by n.

How to run through a 2d array with a single loop?

I was wondering if I could write this very thing but with one single loop, instead of two?
for (int row = 0; row < matrix.length; row++) {
for (int col = 0; col < matrix[0].length; col++) {
if ((row + col) % 2 == 0) {
System.out.print(matrix[row][col] + ", ");
sum += matrix[row][col];
}
}
System.out.println("with a sum of " + sum);
}
Actually just ignore the body of the loop.. It's totally irrelevant, I have no idea whatsoever why I included it.. How to somehow combine the two for loops is my question.
Just keep it simple, if possible. Thank you!
You can, though it's inefficient:
for(int i = 0 ; i < matrix.length * matrix[0].length ; i++)
sum += matrix[i % matrix.length][i / matrix.length];
The basic idea would be to map each index to a value in a 2d-number space, using the fact that we know the length of each "row" of the array (matrix.length). We can compose a single index, that uniquely identifies two indices matrix[x][y], by z = x + y * matrix.length. The reverse of this would then be:
x = z % matrix.length
y = z / matrix.length
This depiction would be complete, e.g. each z in [0 , matrix.length * matrix[0].length) would identify exactly one pair of indices, thus we can use it here.
Paul's answer is initially how I thought to do it. But there is the slight restriction that you need to have a rectangular two-dimensional array (i.e. the sub-arrays are all the same length). If you're modelling a "matrix", this is likely to be the case, but more generally you may want to sum up non-rectangular arrays.
A way around this is to do something like this:
for (int r = 0, c = 0; r < matrix.length;) {
if (c < matrix[r].length) {
sum += matrix[r][c];
++c;
} else {
c = 0;
++r;
}
}
Although it's getting a bit messy. I'd just go for a nested loop instead.

Categories