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,137