Level Up Your Coding Skills & Crack Interviews — Save up to 50% or more on Educative.io Today! Claim Discount

Arrow
Table of contents

Permutations

Permutations show up all the time in coding interviews, specifically by MAANG (Meta, Google, Microsoft, Amazon, and Apple). This is because they test two core skills at once: exploring a search space systematically and keeping your solution correct under lots of branching choices. In this problem, you’re asked to generate every ordering of a set of distinct integers, which is a classic setup for recursion and backtracking.

Interviewers like it because the brute force idea is easy to say, but the real challenge is implementing it cleanly without duplicates, missed cases, or messy extra data structures. If you can solve permutations confidently, you’re also building the same mindset you’ll use for subsets, combinations, and many “try all possibilities” problems.

Problem statement

You’re given an array nums of distinct integers. Return all the possible permutations of those integers, in any order.

Permutations are all possible orderings of a set of items. For example, for [1, 2, 3], permutations include [1, 2, 3], [1, 3, 2], [2, 1, 3], etc.

Constraints:

  • 1 <= nums.length <= 6
  • -10 <= nums[i] <= 10
  • All the integers of nums are unique.

Examples

InputOutputExplanation
[4, 8][[4,8],[8,4]]With 2 numbers, there are 2! = 2 permutations.
[-1, 0, 2][[-1,0,2],[-1,2,0],[0,-1,2],[0,2,-1],[2,-1,0],[2,0,-1]]With 3 numbers, there are 3! = 6 permutations.
[10, 3, 7][[10,3,7],[10,7,3],[3,10,7],[3,7,10],[7,10,3],[7,3,10]]Same 3-element case, just different values.
[5][[5]]With 1 number, only one ordering exists.
[2, 9, 1, 6]24 permutations (not listed)With 4 numbers, there are 4! = 24 permutations, so listing all is lengthy.

How permutation works?

If we recall the classic idea of permutations, they are formed by making a sequence of choices. For an array of n distinct numbers, the first position can be filled in n different ways. After we place one number, it can’t be used again in the same arrangement, so the second position has n−1 remaining choices, then n−2, and so on until only one number is left. This is exactly why there are n! total permutations.

× (n−1) × (n−2) × ⋯ × 1 = n!

Optimized solution using Backtracking

To solve the permutation problem, think of it as building the answer one position at a time from left to right. At each step, you decide which number should go in the current position, and once that choice is made, you move forward to arrange the remaining positions using the remaining numbers. This approach mirrors the exact counting logic behind permutations and avoids inefficient strategies like randomly shuffling or generating extra results and filtering them later.

A clean and efficient way to implement this idea is backtracking with in-place swapping. When you are at index i, you treat it as the position you are currently fixing. You try every possible number for that position by swapping nums[i] with each element from index i onward. Each swap brings a different number into the current position while keeping the rest of the numbers available for future positions. After performing the swap, you recurse to fill the next index. When the recursion reaches the end of the array, the current arrangement is a complete permutation, so you store a copy of it. Then you undo the swap to restore the array to its previous state before trying the next option. This repeated “choose, explore, undo” process is the essence of backtracking and, when the input elements are distinct, it generates every valid permutation exactly once.

Algorithm steps

  1. Make an empty list result to store all permutations, and set n as the length of nums.
  2. Start recursion with backtrack(first = 0), where first means the index we are currently fixing. Inside backtrack:
    1. If first == n, it means every position is fixed, so copy the current nums and add it to result.
    2. Otherwise, for every index i from first to n-1, try placing nums[i] into position first.
      1. Swap nums[first] and nums[i] to bring a new number into the current fixed position.
      2. Call backtrack(first + 1) to move to the next index and decide which number should be placed there, using the remaining unfixed numbers.
      3. Swap back nums[first] and nums[i] to restore the array before trying the next i.
  3. When all choices are explored, return result, which now contains every permutation.

The slides below will help you better understand the solution.

1 / 13

Python code for the optimized solution

Here’s the Python code for the optimized solution using backtracking and in-place swapping.

Time complexity

The algorithm produces every possible permutation, and for n distinct numbers there are n! different permutations. That already means we must do work proportional to n!, because we can’t output fewer than that.

Additionally, to store each permutation we create a copy of the whole list. Copying a list of length n takes O(n) time. As this copy happens once for each of the n! permutations, the total copying cost is:

  • O(n) work per permutation
  • repeated n! times

So, the overall time complexity becomes O(n × n!).

Space complexity

The auxiliary space complexity is O(n) (excluding the output list) because the recursion can go as deep as n calls and the algorithm only uses a constant amount of extra space besides that.

Common mistakes to avoid

Keep an eye for these common mistakes:

  • Modifying the input without restoring it: The core of backtracking is explore and return. If you swap two elements or mark a number as used, you must undo that action after the recursive call. Failing to un-swap or un-mark will corrupt the state for the next branch of the recursion tree, leading to missing or incorrect results.
  • Miscalculating time complexity: Do not simply say the time complexity is O(n!). While there are n! permutations, you perform work at each step. Specifically, when you reach the base case, copying an array of size n into your results takes O(n) time. Therefore, the total time complexity is O(n x n!).
  • Neglecting the recursion stack in space complexity: When asked about space complexity, candidates often forget the call stack. Even if you use an in-place swapping method (which uses O(1) extra auxiliary space for the array itself), the recursion depth is n. Therefore, the space complexity is O(n) due to the stack frames.

Frequently Asked Questions

What if the input array contains duplicate numbers?

The swapping logic might not work here. The best way is to sort the array first and skip the current number if it’s the same as the previous one at that recursion level, or use a frequency map to track available counts.

How can you generate permutations in lexicographical (sorted) order?

Instead of swapping, you should pick elements in sorted order from the remaining pool at each step. This ensures the left-most values are always the smallest possible, resulting in sorted output.

Can this be solved iteratively instead of recursively?

Yes, using lexicographical next-permutation logic. You find the rightmost pair where nums[i] < nums[i+1], swap nums[i] with the next largest value to its right, and reverse the remaining suffix. This uses O(1) auxiliary space.

What is the difference between Permutations and Subsets?

In Permutations, order matters and you use all elements (e.g., [1, 2] and [2, 1]). In Subsets, order does not matter, and you use any number of elements (e.g., {1, 2} is the same as {2, 1}, and {1} is also a valid result).

Share with others:

Leave a Reply

Your email address will not be published. Required fields are marked *