Reputation: 1548
My aim is to find all permutations of a 64 byte array, and for each permutation check if after performing a function F, it is equal to given byte array.
Consider a Small scale Example: Suppose I have 1234, I would like to generate all the permutations of a 4 digit number _ _ _ _ and check each time if it equals 1234
My first thought was to implement a recursive function to generate the permutations. But considering the size, The stack will overflow.
Any efficient way to generate all the permutations? Given Java has large number of libraries?
Upvotes: 3
Views: 2734
Reputation: 43322
As for non-recursive, this answer might help: Permutation algorithm without recursion? Java
As for the simple example, here is a recursive solution that I worked out:
public class Solution {
public List<List<Integer>> permute(int[] num) {
boolean[] used = new boolean[num.length];
for (int i = 0; i < used.length; i ++) used[i] = false;
List<List<Integer>> output = new ArrayList<List<Integer>>();
ArrayList<Integer> temp = new ArrayList<Integer>();
permuteHelper(num, 0, used, output, temp);
return output;
}
public void permuteHelper(int[] num, int level, boolean[] used, List<List<Integer>> output, ArrayList<Integer> temp){
if (level == num.length){
output.add(new ArrayList<Integer>(temp));
}
else{
for (int i = 0; i < num.length; i++){
if (!used[i]){
temp.add(num[i]);
used[i] = true;
permuteHelper(num, level+1, used, output, temp);
used[i] = false;
temp.remove(temp.size()-1);
}
}
}
}
}
Edit: 10 seems to be the max input that completes in a reasonable amount of time for the recursive approach.
With an input array of length 10:
Permutation execution time in milliseconds: 3380
Upvotes: 2
Reputation: 16039
If I understood correctly, you need to generate all the 64! permutations of a 64 byte array, that is:
64! = 126886932185884164103433389335161480802865516174545192198801894375214704230400000000000000 permutations!
If every permutation and comparison takes one millisecond (worst case time scenario) to be calculated, you'll need:
4023558225072430368576654912961741527234446859923426946943236123009091331506849.3150684931506849315 years to calculate them all in one machine! (The 100th of this monstrosity if every permutation takes a 100th of a millisecond).
So, you should reduce the search space of your problem by applying some heuristics instead of naively listing all possible solutions.
After you reduce your search space to a more treatable number number, like for example: 14! (2 years of computation time in the "one millisecond" case scenario), you can split your calculations over several machines by using Factoradics (an implementation here) to calculate the starting and ending permutation for every machine and then use the following code in every node (an implementation of the Knuth's L-algorithm) to search the solution in every machine:
public class Perm {
private static byte[] sequenceToMatch;
private static byte[] startSequence;
private static byte[] endingSequence;
private static final int SEQUENCE_LENGTH = 64;
public static void main(String... args) {
final int N = 3;
startSequence = readSequence(args[0]);
endingSequence = readSequence(args[1]);
sequenceToMatch = readSequence(args[2]);
permutations();
}
private static boolean sequencesMatch(byte[] s1, byte[] s2) {
for (int i = 0; i < SEQUENCE_LENGTH; i++) {
if (s1[i] != s2[i]) {
return false;
}
}
return true;
}
private static byte[] readSequence(String argument) {
String[] sBytes = argument.split(",");
byte[] bytes = new byte[SEQUENCE_LENGTH];
int i = 0;
for (String sByte : sBytes) {
bytes[i++] = Byte.parseByte(sByte, 10);
}
return bytes;
}
private static void swap(byte[] elements, int i, int j) {
byte temp = elements[i];
elements[i] = elements[j];
elements[j] = temp;
}
/**
* Reverses the elements of an array (in place) from the start index to the end index
*/
private static void reverse(byte[] array, int startIndex, int endIndex) {
int size = endIndex + 1 - startIndex;
int limit = startIndex + size / 2;
for (int i = startIndex; i < limit; i++) {
// swap(array, i, startIndex + (size - 1 - (i - startIndex)));
swap(array, i, 2 * startIndex + size - 1 - i);
}
}
/**
* Implements the Knuth's L-Algorithm permutation algorithm
* modifying the collection in place
*/
private static void permutations() {
byte[] sequence = startSequence;
if (sequencesMatch(sequence, sequenceToMatch)) {
System.out.println("Solution found!");
return;
}
// For every possible permutation
while (!sequencesMatch(sequence, endingSequence)) {
// Iterate the array from right to left in search
// of the first couple of elements that are in ascending order
for (int i = SEQUENCE_LENGTH - 1; i >= 1; i--) {
// If the elements i and i - 1 are in ascending order
if (sequence[i - 1] < sequence[i]) {
// Then the index "i - 1" becomes our pivot index
int pivotIndex = i - 1;
// Scan the elements at the right of the pivot (again, from right to left)
// in search of the first element that is bigger
// than the pivot and, if found, swap it
for (int j = SEQUENCE_LENGTH - 1; j > pivotIndex; j--) {
if (sequence[j] > sequence[pivotIndex]) {
swap(sequence, j, pivotIndex);
break;
}
}
// Now reverse the elements from the right of the pivot index
// (this nice touch to the algorithm avoids the recursion)
reverse(sequence, pivotIndex + 1, SEQUENCE_LENGTH - 1);
break;
}
}
if (sequencesMatch(sequence, sequenceToMatch)) {
System.out.println("Solution found!");
return;
}
}
}
}
Upvotes: 3
Reputation: 3795
Edit: I had a quick search for possible implementations and came across an algorithm suggested as a part of an answer to another question.
Below is a code developed by: https://stackoverflow.com/users/2132573/jon-b for your convenience. It correctly creates and prints all the permutations of an integer list. You may easily use the same logic with array (Credits go to jon-b !!).
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class HelloWorld {
public static int factorial(int x) {
int f = 1;
while (x > 1) {
f = f * x;
x--;
}
return f;
}
public static List<Integer> permute(List<Integer> list, int iteration) {
if (list.size() <= 1) return list;
int fact = factorial(list.size() - 1);
int first = iteration / fact;
List<Integer> copy = new ArrayList<Integer>(list);
Integer head = copy.remove(first);
int remainder = iteration % fact;
List<Integer> tail = permute(copy, remainder);
tail.add(0, head);
return tail;
}
public static void main(String[] args) throws IOException {
List<Integer> list = Arrays.asList(4, 5, 6, 7);
for (int i = 0; i < 24; i++) {
System.out.println(permute(list, i));
}
}
}
I have tested it in http://www.tutorialspoint.com/compile_java8_online.php and it worked well as is.
Hope that helps!
Upvotes: 1