Compare commits
No commits in common. "a8796ba886a070f56e3e1bcf242831c48e895dec" and "26ff1404a1a1c89729dfc1d10983756f8878bd62" have entirely different histories.
a8796ba886
...
26ff1404a1
@ -1,13 +1,15 @@
|
|||||||
package com.cleverthis.interview;
|
package com.cleverthis.interview;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Brute-forces padlock using lexicographically ordered permutation generation.
|
* Brute-forces padlock using lexicographically ordered permutation generation
|
||||||
*
|
*
|
||||||
* Permutation-generation algorithm documented at: https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order
|
* Algorithm documented at: https://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order
|
||||||
*/
|
*/
|
||||||
public class DumbBruteSolver implements SolverInterface {
|
public class DumbBruteSolver implements SolverInterface {
|
||||||
|
|
||||||
@ -29,7 +31,7 @@ public class DumbBruteSolver implements SolverInterface {
|
|||||||
boolean isCorrect = checkPermutation(currentPermutation, padlockAdapter);
|
boolean isCorrect = checkPermutation(currentPermutation, padlockAdapter);
|
||||||
|
|
||||||
if (!isCorrect) {
|
if (!isCorrect) {
|
||||||
boolean nextPermutationExists = calculateNextPermutation(currentPermutation);
|
boolean nextPermutationExists = calculateNextPermutation(currentPermutation, numpadSize);
|
||||||
if(!nextPermutationExists) {
|
if(!nextPermutationExists) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -58,11 +60,10 @@ public class DumbBruteSolver implements SolverInterface {
|
|||||||
/**
|
/**
|
||||||
* Calculates the next permutation in lexicographic order, based on the algorithm linked on wikipedia
|
* Calculates the next permutation in lexicographic order, based on the algorithm linked on wikipedia
|
||||||
* @param currentPermutation The current permutation to run the algorithm on
|
* @param currentPermutation The current permutation to run the algorithm on
|
||||||
|
* @param numpadSize The number of items in the set to be permuted
|
||||||
* @return true if next permutation successfully generated, false if permutations have been exhausted
|
* @return true if next permutation successfully generated, false if permutations have been exhausted
|
||||||
*/
|
*/
|
||||||
protected boolean calculateNextPermutation(Integer[] currentPermutation) {
|
protected boolean calculateNextPermutation(Integer[] currentPermutation, int numpadSize) {
|
||||||
int numpadSize = currentPermutation.length;
|
|
||||||
|
|
||||||
if(numpadSize < 2) { return false; }
|
if(numpadSize < 2) { return false; }
|
||||||
|
|
||||||
//Integer k, l;
|
//Integer k, l;
|
||||||
|
@ -3,7 +3,7 @@ package com.cleverthis.interview;
|
|||||||
import org.apache.commons.text.similarity.LevenshteinDistance;
|
import org.apache.commons.text.similarity.LevenshteinDistance;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds a single possible padlock passcode permutation in an integer array. This class
|
* A wrapper class that holds possible padlock passcode permutations in an integer array. This class
|
||||||
* overloads the toString() method and is comparable, using its string value to calculate the levenshtein distance and
|
* overloads the toString() method and is comparable, using its string value to calculate the levenshtein distance and
|
||||||
* use those distance values for sorting into a data structure.
|
* use those distance values for sorting into a data structure.
|
||||||
*/
|
*/
|
||||||
@ -50,7 +50,7 @@ public class IntegerLevenshtein implements Comparable<IntegerLevenshtein> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Overridden compareTo method that compares the calculated levenshtein distance between two IntegerLevenshtein objects
|
* Overriden compareTo method that compares the calculated levenshtein distance between two IntegerLevenshtein objects
|
||||||
* @param otherInteger the object to be compared.
|
* @param otherInteger the object to be compared.
|
||||||
* @return The levenshtein distance between the two objects.
|
* @return The levenshtein distance between the two objects.
|
||||||
*/
|
*/
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package com.cleverthis.interview;
|
package com.cleverthis.interview;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This defines the contract that padlocks must conform to.
|
* This defines the interface that padlocks must conform to.
|
||||||
* Concrete implementations will be adapted to this interface contract through concrete adapter classes.
|
* Concrete implementations will be adapted to this interface contract through concrete adapter classes.
|
||||||
*/
|
*/
|
||||||
public interface PadlockAdapter {
|
public interface PadlockAdapter {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package com.cleverthis.interview;
|
package com.cleverthis.interview;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines the contract for padlock-cracking solver implementations
|
* Interface that defines the class signature for solver implementations
|
||||||
*/
|
*/
|
||||||
public interface SolverInterface {
|
public interface SolverInterface {
|
||||||
|
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
package com.cleverthis.interview;
|
package com.cleverthis.interview;
|
||||||
|
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
import org.apache.commons.text.similarity.LevenshteinDistance;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A write-aware brute solver implementation that uses the levenshtein distance to sort passcode permutations
|
* This is a write-aware brute solver implementation that uses the levenshtein distance to sort passcode permutations
|
||||||
* into a tree. Walking the tree in-order (Likely a depth-first traversal internally) results in a naive nearest-neighbor
|
* into a tree. Walking the tree in-order (Likely a depth-first traversal internally) results in a naive nearest-neighbor
|
||||||
* optimization that generally performs well, but may perform poorly in some cases. Heuristic solutions exist that have
|
* optimization that generally performs well, but may perform poorly in some cases. Heuristic solutions exist that have
|
||||||
* acceptable performance, and this is a more naive heuristic implementation.
|
* acceptable performance, and this is a more naive heuristic implementation.
|
||||||
@ -15,7 +17,7 @@ import java.util.TreeSet;
|
|||||||
* A more advanced solution (based on Christofides, or another TSP heuristic) may result in more performance gains, but
|
* A more advanced solution (based on Christofides, or another TSP heuristic) may result in more performance gains, but
|
||||||
* the performance of this nearest-neighbor solution is adequate for the keypad sizes under test. A keypad size of 9
|
* the performance of this nearest-neighbor solution is adequate for the keypad sizes under test. A keypad size of 9
|
||||||
* results in a graph of vertex-count 9!. It's unlikely performance gains from a more intelligent TSP solver would
|
* results in a graph of vertex-count 9!. It's unlikely performance gains from a more intelligent TSP solver would
|
||||||
* offset the performance cost of building a graph and solving for an optimal tour.
|
* offset the performance cost of building a graph and optimizing traversal.
|
||||||
*/
|
*/
|
||||||
public class WriteAwareBruteSolver extends DumbBruteSolver {
|
public class WriteAwareBruteSolver extends DumbBruteSolver {
|
||||||
|
|
||||||
@ -66,8 +68,10 @@ public class WriteAwareBruteSolver extends DumbBruteSolver {
|
|||||||
* @param size The number of keys on the numpad
|
* @param size The number of keys on the numpad
|
||||||
*/
|
*/
|
||||||
protected void createOrderedTree(int size) {
|
protected void createOrderedTree(int size) {
|
||||||
this.numpadSize = size;
|
if(this.numpadSize != size) {
|
||||||
orderedTree.clear();
|
this.numpadSize = size;
|
||||||
|
orderedTree.clear();
|
||||||
|
}
|
||||||
|
|
||||||
Integer[] currentPermutation = new Integer[numpadSize];
|
Integer[] currentPermutation = new Integer[numpadSize];
|
||||||
for(int i = 0; i < numpadSize; i++) {
|
for(int i = 0; i < numpadSize; i++) {
|
||||||
@ -80,7 +84,7 @@ public class WriteAwareBruteSolver extends DumbBruteSolver {
|
|||||||
IntegerLevenshtein levenshteinPermutation = new IntegerLevenshtein(numpadSize);
|
IntegerLevenshtein levenshteinPermutation = new IntegerLevenshtein(numpadSize);
|
||||||
levenshteinPermutation.setIntegerData(currentPermutation);
|
levenshteinPermutation.setIntegerData(currentPermutation);
|
||||||
orderedTree.add(levenshteinPermutation);
|
orderedTree.add(levenshteinPermutation);
|
||||||
morePermutationsExist = this.calculateNextPermutation(currentPermutation);
|
morePermutationsExist = this.calculateNextPermutation(currentPermutation, numpadSize);
|
||||||
} while(morePermutationsExist);
|
} while(morePermutationsExist);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,7 @@ public class DumbBruteSolverTest extends SolutionTestBase {
|
|||||||
Integer[] permutation = new Integer[] {1, 2, 3, 4};
|
Integer[] permutation = new Integer[] {1, 2, 3, 4};
|
||||||
Integer[] correctPermutation = new Integer[] {1, 2, 4, 3};
|
Integer[] correctPermutation = new Integer[] {1, 2, 4, 3};
|
||||||
|
|
||||||
dumbSolver.calculateNextPermutation(permutation);
|
dumbSolver.calculateNextPermutation(permutation, 4);
|
||||||
|
|
||||||
assertArrayEquals(permutation, correctPermutation);
|
assertArrayEquals(permutation, correctPermutation);
|
||||||
}
|
}
|
||||||
@ -59,7 +59,7 @@ public class DumbBruteSolverTest extends SolutionTestBase {
|
|||||||
Integer[] correctPermutation = new Integer[] {1, 3, 2, 4};
|
Integer[] correctPermutation = new Integer[] {1, 3, 2, 4};
|
||||||
|
|
||||||
for(int i = 0; i < 2; i++) {
|
for(int i = 0; i < 2; i++) {
|
||||||
dumbSolver.calculateNextPermutation(permutation);
|
dumbSolver.calculateNextPermutation(permutation, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
assertArrayEquals(permutation, correctPermutation);
|
assertArrayEquals(permutation, correctPermutation);
|
||||||
@ -76,7 +76,7 @@ public class DumbBruteSolverTest extends SolutionTestBase {
|
|||||||
Integer[] correctPermutation = new Integer[] {4, 3, 2, 1};
|
Integer[] correctPermutation = new Integer[] {4, 3, 2, 1};
|
||||||
|
|
||||||
for(int i = 0; i < 23; i++) {
|
for(int i = 0; i < 23; i++) {
|
||||||
dumbSolver.calculateNextPermutation(permutation);
|
dumbSolver.calculateNextPermutation(permutation, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
assertArrayEquals(permutation, correctPermutation);
|
assertArrayEquals(permutation, correctPermutation);
|
||||||
@ -93,10 +93,10 @@ public class DumbBruteSolverTest extends SolutionTestBase {
|
|||||||
Integer[] permutation = new Integer[] {1, 2, 3, 4};
|
Integer[] permutation = new Integer[] {1, 2, 3, 4};
|
||||||
|
|
||||||
for(int i = 0; i < 23; i++) {
|
for(int i = 0; i < 23; i++) {
|
||||||
assertTrue(dumbSolver.calculateNextPermutation(permutation));
|
assertTrue(dumbSolver.calculateNextPermutation(permutation, 4));
|
||||||
}
|
}
|
||||||
|
|
||||||
assertFalse(dumbSolver.calculateNextPermutation(permutation));
|
assertFalse(dumbSolver.calculateNextPermutation(permutation, 4));
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.cleverthis.interview;
|
package com.cleverthis.interview;
|
||||||
|
|
||||||
|
import com.cleverthis.interview.padlock.PadlockImpl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performance test but not mean to run in unit test.
|
* Performance test but not mean to run in unit test.
|
||||||
*/
|
*/
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.cleverthis.interview;
|
package com.cleverthis.interview;
|
||||||
|
|
||||||
|
import com.cleverthis.interview.padlock.PadlockImpl;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
Loading…
Reference in New Issue
Block a user