Skip to content

Instantly share code, notes, and snippets.

@MikeDigitize
Created January 22, 2019 17:40
Show Gist options
  • Save MikeDigitize/ae7cc468d3de6ed4b3be7cf3e3a16ba2 to your computer and use it in GitHub Desktop.
Save MikeDigitize/ae7cc468d3de6ed4b3be7cf3e3a16ba2 to your computer and use it in GitHub Desktop.
Get all unique string permutations using non-mathematical recursion vs mathematical recursion
function getNumberOfPermutations(input) {
if (!input.length) {
return 0;
}
let { length } = input;
let dividend = getFactorial(length);
let divisor = 0
while (input.length) {
let firstChar = input[0];
let occurences = getNumberOfOccurencesInString(input, firstChar);
if (occurences > 1) {
divisor += occurences;
}
input = input.replace(new RegExp(firstChar, 'g'), '');
}
return dividend / (divisor || 1);
}
function getNumberOfOccurencesInString(input, valueToFind) {
return input.split('').filter(str => valueToFind === str).length;
}
function getFactorial(x) {
if (x === 0) {
return 1;
}
return x * getFactorial(x - 1);
}
function inputToObject(input) {
let result = {}
while (input.length) {
let firstChar = input[0];
result[firstChar] = getNumberOfOccurencesInString(input, firstChar);
input = input.replace(new RegExp(firstChar, 'g'), '');
}
return result;
}
function getFirstAvailableCharacter(input = {}, startFrom = 0) {
return Object
.keys(input)
.filter((key, i) => i >= startFrom && input[key] > 0)
.shift()
|| null;
}
function isInputObjectStillActive(input) {
return !!Object.keys(input).filter(key => input[key] > 0).length;
}
function decrementCharacterCount(input = {}, charToDecrement = '') {
let nextInput = Object.assign({}, input);
if (nextInput[charToDecrement] > 0) {
nextInput[charToDecrement]--;
}
return nextInput;
}
function getPermutations(input) {
let inputObject = inputToObject(input);
let stack = [];
let stackLevel = 0;
let result = [];
let results = [];
let perms = getNumberOfPermutations(input);
stack.push({ inputObject, startFrom: 0 });
while (results.length < perms) {
inputObject = stack[stackLevel].inputObject;
startFrom = stack[stackLevel].startFrom;
let firstAvailableChar = getFirstAvailableCharacter(inputObject, startFrom);
if (firstAvailableChar) {
result[stackLevel] = firstAvailableChar;
stack[stackLevel].startFrom = Object.keys(inputObject).indexOf(firstAvailableChar) + 1;
inputObject = decrementCharacterCount(inputObject, firstAvailableChar);
stackLevel++;
stack[stackLevel] = { inputObject, startFrom: 0 };
}
else {
if (!isInputObjectStillActive(inputObject)) {
results.push(result.join(''));
}
stackLevel--;
}
}
return results;
}
getPermutations('AABC');
function getPerms(input) {
let inputUsesOnlyOneChar =
!input
.split('')
.filter(char => char !== input[0])
.length;
if (inputUsesOnlyOneChar) {
return [input];
}
let results = [];
for (let i = 0; i < input.length; i++) {
let currentChar = input[i];
let inputStartToCurrentChar = input.substr(0, i);
let currentCharToInputEnd = input.substr(i + 1, input.length);
let inputWithoutCurrentChar = `${inputStartToCurrentChar}${currentCharToInputEnd}`;
let resultsPrependedWithCurrentChar = perm(inputWithoutCurrentChar).map(result => `${currentChar}${result}`);
results = results.concat(resultsPrependedWithCurrentChar);
}
return [...new Set(results)];
}
getPerms('AABC');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment