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 ITERATIVE 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
// 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); // Other options include `.slice` and `Array.from` methods
// 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 Variation
// 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();
}
Possible Recursive Solution Variation 2
// Adapted from Griffin Telljohann's Code Wars solution
function permutations(str) {
if (!str.length) { return ['']; }
// Split the input string and map over each character
const initial = str.split('').map((char, idx, arr) => {
// Recursively create permutations of each string minus the selected `char`acter
const subPermutations = permutations(remove(arr, char).join(''))
// Map over each subPermutation and return that with the selected `char`acter appended to it
return subPermutations.map(str => char + str);
}).reduce((prev, curr) => prev.concat(curr), []) // Concatenate each new array of permutations to the previous one
return removeDuplicates(initial); // Filter out the dupes, sort, and return
}
// Takes an array and a `char`acter and returns it without said `char`acter
function remove(arr, char) {
const idx = arr.indexOf(char);
return [...arr.slice(0, idx), ...arr.slice(idx + 1)];
}
// Filters out dupes and sorts in alphabetical order
function removeDuplicates(arr) {
return arr.filter((el, idx) => arr.indexOf(el) === idx).sort();
}
Conclusion
Know your string and array methods.
Consider breaking a problem into smaller pieces.
String Permutations
By tessaslides
String Permutations
Technical interview problem on generating string permutations
- 1,212