R
E
A
C
T
O
xamples
epeat
ode
pproach
ptimize
est
{String Permutations}
The Challenge
Given a string, return an array of all the permutations of that string.
All permutations must be the same length as the original string but do not need to be real words.
stringPermutations('one') //should return [ 'eon', 'eno' 'neo', 'noe', 'one', 'oen']
stringPermutations('app') //should return [ 'app','pap','ppa']
stringPermutations('nn') //should return [ 'nn' ]
Notes
- The returned array should contain only unique values
- The returned array should be alphabetically sorted
Approach
A string of one character has one permutation
'a' -> [ 'a' ]
For each additional letter, add it to each possible space in the current results
stringPermutations('abc')
insert 'a'
[ 'a' ]
Approach
A string of one character has one permutation
'a' -> [ 'a' ]
For each additional letter, add it to each possible space in the current results
stringPermutations('abc')
insert 'b'
'b'
[ 'a' ]
'ab' ]
[ 'ba
Approach
For each additional letter, add it to each possible space in the current results
stringPermutations('abc')
'c'
[ 'ba', 'ab' ]
insert 'c'
[ 'cba', 'bca', 'bac'
'cab', 'acb', 'abc ]
Possible Solution
function stringPermutations(str) {
let permutations = [];
const letters = str.split('');
permutations.push([letters.shift()]) // Adds first letter (as a subarray) to `permutations`
while (letters.length) {
const nextLetter = letters.shift(); // Takes the next potential letter off the `letters` array
const tempermutations = []; // Temporary list of permutated results
permutations.forEach(currentPerm => { // For each permutation in progress
for (let i = 0; i <= currentPerm.length; ++i) { // As long as the letters already processed
const currentCopy = Array.from(currentPerm); // Copy `currentPerm` to prep for mutation
// Add `nextLetter` at each possible position during each iteration of the `for` loop
currentCopy.splice(i, 0, nextLetter)
// Add the mutated copy to the temporary list of permutations
tempermutations.push(currentCopy);
}
});
// Overwrite previous permutations which are now one letter short
permutations = tempermutations;
}
// Turn each permutated subarray back into a string
permutations = permutations.map(wordArr => wordArr.join(''));
// Filter out non-unique permutations, sort the array into alphabetical order, then return
return permutations.filter((el, idx) => permutations.indexOf(el) === idx).sort();
}
Possible Recursive Solution
function recursiveStringPermutations(letters) {
const permutations = [];
getPerms(letters, []);
function getPerms(letters, currentPerm) {
// Splits OG input string into array
if (typeof letters === 'string') letters = letters.split('');
// BASE CASE: Once all letters are moved from `letters` to `currentPerm` join them & push into `permutations` array
if (!letters.length) permutations.push(currentPerm.join(''));
for (let i = 0; i < letters.length; ++i) {
// Through each recursive iteration, move currentLetter from `letters` to `currentPerm`
const currentLetter = letters.splice(i, 1);
currentPerm.push(currentLetter);
getPerms(letters, currentPerm); // Recursively goes to BASE CASE
currentPerm.pop(); // Pop the currentLetter back off the array
letters.splice(i, 0, currentLetter); // Often leads back to BASE CASE w/no tangible progress
// However SOMETIMES moves position of NEXT letter and starts the permutation cycle all over again
}
}
// Filter out non-unique permutations, sort the array into alphabetical order, then return
return permutations.filter((el, idx) => permutations.indexOf(el) === idx).sort();
}
Possible Recursive Solution 2
// Adapted from: http://www.thatjsdude.com/interview/js1.html#permutation
function permutations(str){
// Convert `str` to an array
const arr = str.split(''),
len = arr.length,
perms = [];
let rest,
picked,
restPerms,
next;
// BASE CASE: If there are no 'rest' characters left, return `['']`
if (len === 0) return [str];
for (let i = 0; i < len; ++i) {
// Create an array copy of all letters in current order
rest = Object.create(arr);
// Remove & reserve the 1st letter whilst we permute the rest
picked = rest.splice(i, 1);
// Create the permuted string variations recursively
restPerms = permutations(rest.join(''));
for (let k = 0, kLen = restPerms.length; k < kLen; ++k) {
// Concatenate each variation of the 'rest' letters to the reserved letter
next = picked.concat(restPerms[k]);
// Push each variation into the permutations list
perms.push(next.join(''));
}
}
// Filter out non-unique permutations, sort the array into alphabetical order, then return
return perms.filter((el, idx) => perms.indexOf(el) === idx).sort();
}
Possible Recursive Solution 2.5
// Adapted from Galen Corey's 1610GHA Solution
function getPerms(lettArray){
let perms = [];
// BASE CASE: If we're on the last letter return the letter
if (lettArray.length === 1) return lettArray;
lettArray.forEach((char, idx) => {
// Make a copy of the current array;
const rest = lettArray.slice();
// Remove the idx-th character (`char`) in the array
rest.splice(idx, 1);
// Recursively concatenate the 'rest' variations to the current character
const subPerms = getPerms(rest).map(subPerm => char + subPerm);
// Concatenate all the new permutations into the `perms` array
perms = [...perms, ...subPerms];
})
return perms
}
function getPermsWrapper(str){
// Turn the input string into an array and call `getPerms` on it
const allPerms = getPerms(str.split(''));
// Filter out repeats and sort into alphabetical order
return allPerms.filter((word, idx) => allPerms.indexOf(word) === idx).sort();
}
Conclusion
Know your string and array methods.
Consider breaking a problem into smaller pieces.
String Permutations (LEGACY)
By tessaslides
String Permutations (LEGACY)
Technical interview problem on generating string permutations
- 1,259