Finding every possible arrangement of a string's characters is a staple backtracking problem that comes up often in technical interviews. A string of length n has n! (n factorial) distinct permutations, so for a string like "abc" there are 3! = 6 arrangements, and for a 10-character string there would already be over 3.6 million — which is why this is mostly an exercise in correct recursion rather than something you'd run on long strings in production.

Permutations of a String Using Backtracking

The idea: pick each remaining character in turn to go first, then recursively find all permutations of the characters that are left. Each recursive call shrinks the "remaining characters" pool by one, and the base case is an empty remaining string, which means you've built one complete permutation.

function findPermutations(str, prefix = "", result = []) {
  if (str.length === 0) {
    result.push(prefix); // base case: nothing left to place, prefix is a full permutation
    return result;
  }

  for (let i = 0; i < str.length; i++) {
    const remaining = str.slice(0, i) + str.slice(i + 1); // string minus the chosen character
    findPermutations(remaining, prefix + str[i], result);
  }

  return result;
}

const permutations = findPermutations("abc");
console.log(permutations);
console.log("Total:", permutations.length);

Output:

[ 'abc', 'acb', 'bac', 'bca', 'cab', 'cba' ]
Total: 6


Handling Duplicate Characters

If the input string has repeated characters (like "aab"), the function above will generate duplicate permutations, since it treats each position as distinct even when the characters match. A quick fix is to collect the results into a Set before returning:

const unique = [...new Set(findPermutations("aab"))];
console.log(unique);

Output:

[ 'aab', 'aba', 'baa' ]

This is backtracking in its purest form: try a choice (place a character), recurse on the smaller remaining problem, and the function naturally "backtracks" to try the next choice once a branch of the for loop finishes. The time complexity is O(n! × n) — n! permutations, each taking O(n) work to build via slicing and concatenation — so this approach is fine for short strings but isn't meant to scale to long input.