I've implemented an algorithm that generates all variations of a matrix of size \$M*N\$. My approach is that I see a matrix as a list where the position of elements can be calculated from the position in the matrix. By doing that I can reduce the problem into generating all variations of a list of length \$M*N\$.
The algorithm computes the variations recursively. I start with an empty list and pass it to my function. The list is copied. The copied list gets a 0
and the original list gets a 1
added. Then I call the function recursively with each of both resulting lists. The process is repeated until the length \$M*N\$ is reached. At this point, I have the set of all variations (size = \2ドル^{M*N}\$).
Now I can compute the arrays from those variations and compose the resulting matrices.
Here is the implementation:
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Deque;
class Main {
static void addVariations(Deque<int[]> stack, int[] variation, int index) {
if (index >= 0) {
// clone for next recursion
int[] variationClone = variation.clone();
// one gets 0, the other 1 at index
variation[index] = 0;
variationClone[index] = 1;
// next recursion
addVariations(stack, variation, index - 1);
addVariations(stack, variationClone, index - 1);
}
else {
stack.push(variation);
}
}
static Deque<int[][]> getVariations(int M, int N) {
int variationLength = M*N;
// get all variations that the matrices are base on
// there are n^r, 2^variationLength of them
Deque<int[]> variations = new ArrayDeque<>();
addVariations(variations, new int[variationLength], variationLength - 1);
// container for resulting matrices
Deque<int[][]> variationMatrices = new ArrayDeque<>();
// for each matrix
for (int i = variations.size() - 1; i >= 0 ; i--) {
int[][] matrix = new int[N][M];
int[] variation = variations.pop();
// for each row add part of variation
for (int j = 0; j < matrix.length; j++) {
matrix[j] = Arrays.copyOfRange(variation, j*M, (j + 1)*M);
}
// and push the matrix to result
variationMatrices.push(matrix);
}
return variationMatrices;
}
public static void main(String[] args) {
int N = 2, M = 2;
Deque<int[][]> variations = getVariations(N, M);
variations.forEach(v -> {
System.out.println("----");
for (int i = 0; i < v.length; i++) {
System.out.println(Arrays.toString(v[i]));
}
System.out.println("----");
});
}
}
I'd be very happy to get tipps on how to improve the code. I'm especially interested in style and readability of my code.
The expected output is the set of variations. Each variation is a matrix containing only 0
s and 1
s. Each matrix is represented as a 2-dimensional array where each row is an array.
So e.g. the output for a \2ドル*2\$ matrix is supposed to be:
[[0, 0], [0, 0]]
,
[[1, 0], [0, 0]]
,
[[0, 1], [0, 0]]
,
[[1, 1], [0, 0]]
,
[[0, 0], [1, 0]]
,
[[1, 0], [1, 0]]
,
[[0, 1], [1, 0]]
,
[[1, 1], [1, 0]]
,
[[0, 0], [0, 1]]
,
[[1, 0], [0, 1]]
,
[[0, 1], [0, 1]]
,
[[1, 1], [0, 1]]
,
[[0, 0], [1, 1]]
,
[[1, 0], [1, 1]]
,
[[0, 1], [1, 1]]
,
[[1, 1], [1, 1]]
The order doesn't matter.
-
\$\begingroup\$ Doesn't look like permutations to me. Can you add a small example of the expected output? \$\endgroup\$vnp– vnp2020年05月17日 21:51:57 +00:00Commented May 17, 2020 at 21:51
-
\$\begingroup\$ @vnp Thank you, you are right, it's about variations, not permutations. I've updated the question. \$\endgroup\$akuzminykh– akuzminykh2020年05月18日 13:50:01 +00:00Commented May 18, 2020 at 13:50
-
\$\begingroup\$ A request was made to add a small example of the expected output. Would it be possible for you to add this? \$\endgroup\$Mast– Mast ♦2020年05月18日 14:08:15 +00:00Commented May 18, 2020 at 14:08
-
\$\begingroup\$ @Mast There you go. \$\endgroup\$akuzminykh– akuzminykh2020年05月18日 14:17:30 +00:00Commented May 18, 2020 at 14:17
-
\$\begingroup\$ How about just implementing a method that visualizes the binary representation of any integer between 0 and 2^(M*N) as a 2D array? \$\endgroup\$TorbenPutkonen– TorbenPutkonen2020年05月18日 15:54:09 +00:00Commented May 18, 2020 at 15:54
1 Answer 1
The code does not produce permutations. It produces the subsets of \$M * N\$-strong set. Below assumes that it is the goal of the code.
Recursive solution is correct, but may take too much memory (there are exponentially many subsets, namely \2ドル^{N*M}\$ of them). I strongly recommend to switch to an iterative approach:
bool next_subset(int [] subset) {
for (int i = 0; i < subset.size(); i++) {
if subset[i] == 1) {
subset[i] == 0;
} else {
subset[i] = 1;
return true;
}
}
return false;
}
which takes the same time, linear memory, and can be used to stream the subsets one-by-one.
-
1\$\begingroup\$ The latest edit invalidates your answer. However, since you point out in your answer that the code didn't do what it should've been doing, perhaps it's better to simply scrap the first line of your answer instead of rolling-back the edit. \$\endgroup\$2020年05月18日 13:53:07 +00:00Commented May 18, 2020 at 13:53
Explore related questions
See similar questions with these tags.