Talentd
FleetCode
Make and follow sheets.Sign in

Permutations solution and explanation

MediumArrayBacktracking5 min read82.3% acceptanceUpdated 9 Apr 2026
Backtracking: Permutations - Leetcode 46 - PythonNeetCode · 9:43 · 422K viewsWatch on YouTube
9 more videos on this problem
  1. Backtracking: Permutations - Leetcode 46 - PythonNeetCode · 9:43 · 422K views
  2. Permutations - Leetcode 46 - PythonNeetCodeIO · 11:58 · 132K views
  3. Leetcode 46. Permutations : Introduction to backtrackingComputerBread · 10:06 · 128K views
  4. Permutations (LeetCode 46) | Full solution with backtracking examples | Interview | Study AlgorithmsNikhil Lohia · 16:55 · 120K views
  5. Permutations | INTUITIVE | Backtracking Template | Two Ways | Similar Problems | Leetcode 46codestorywithMIK · 36:36 · 49K views
  6. Permutations - Leetcode 46 - Recursive Backtracking (Python)Greg Hogg · 9:42 · 41K views
  7. Permutations | Live Coding with Explanation | Leetcode #46Algorithms Made Easy · 5:45 · 23K views
  8. LEETCODE 46 (JAVASCRIPT) | PERMUTATIONS IAndy Gala · 14:49 · 14K views
  9. Permutations leetcode java - Leetcode 46 PermutationsJK Codes · 7:31 · 2K views
  10. Permutations - 46. LeetCode - JavaTeddy Smith · 8:54 · 1K views

The problem

Given an array nums of distinct integers, return all the possible permutations. You can return the answer in any order.

Example 1:

Input: nums = [1,2,3]
Output: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]

Example 2:

Input: nums = [0,1]
Output: [[0,1],[1,0]]

Example 3:

Input: nums = [1]
Output: [[1]]

Constraints:

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

Approach overview

Problem Overview: Given an array of distinct integers, return all possible permutations of the numbers. Each permutation represents a different ordering of the same elements, and the result must include every possible arrangement.

Approach 1: Backtracking (Time: O(n! * n), Space: O(n))

This problem naturally fits backtracking. You build permutations incrementally by choosing an unused element, adding it to the current path, and recursively exploring further choices. A boolean used[] array or in-place swapping ensures each element appears only once in the current permutation.

The key insight is that every position in the permutation can be filled by any unused element. For each recursive level, iterate through the array, pick an unused number, append it to the current permutation, and recurse. Once the permutation length reaches n, add a copy to the result list. Then backtrack by removing the last element and marking it unused.

This generates exactly n! permutations. Copying each permutation takes O(n), which leads to an overall time complexity of O(n! * n). The recursion depth is O(n), and auxiliary space is mainly the recursion stack and the current permutation. Backtracking is the most common interview solution and heavily relies on concepts from recursion and array traversal.

Approach 2: Iterative Permutation Generation (Time: O(n! * n), Space: O(n!))

An iterative strategy builds permutations progressively. Start with a list containing an empty permutation. For each number in the input array, insert it into every possible position of every existing permutation. If a permutation has length k, inserting the new number produces k + 1 new permutations.

Example: starting with [ ], inserting 1 gives [1]. Inserting 2 into [1] creates [2,1] and [1,2]. Continue inserting the next element into every position of each existing permutation until all numbers are processed.

This approach avoids recursion and can be easier to reason about in iterative environments. However, it repeatedly copies arrays when inserting elements, which increases memory overhead. The total number of generated permutations is still n!, and each insertion operation costs up to O(n), resulting in O(n! * n) time complexity.

Recommended for interviews: Backtracking is the expected approach. It demonstrates control over recursion, state management, and pruning. Interviewers usually want to see the recursive exploration pattern and proper backtracking logic. The iterative insertion approach is useful as an alternative but appears less frequently in coding interviews.

Approach 1: Backtracking Approach

This approach uses recursion combined with backtracking to generate all possible permutations of the input array. The algorithm works by swapping elements of the array and recursively building permutations by fixing one element at a time until the entire array is permutated.

def permute(nums):
    def backtrack(first=0):
        if first == n:
            output.append(nums[:])
        for i in range(first, n):
            nums[first], nums[i] = nums[i], nums[first]
            backtrack(first + 1)
            nums[first], nums[i] = nums[i], nums[first]

    n = len(nums)
    output = []
    backtrack()
    return output

print(permute([1, 2, 3]))
import java.util.ArrayList;
import java.util.List;

public class Permutations {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> result = new ArrayList<>();
        backtrack(nums, result, new ArrayList<Integer>(), new boolean[nums.length]);
        return result;
    }

    private void backtrack(int[] nums, List<List<Integer>> result, List<Integer> tempList, boolean[] used) {
        if (tempList.size() == nums.length) {
            result.add(new ArrayList<>(tempList));
        } else {
            for (int i = 0; i < nums.length; i++) {
                if (used[i]) continue;
                used[i] = true;
                tempList.add(nums[i]);
                backtrack(nums, result, tempList, used);
                used[i] = false;
                tempList.remove(tempList.size() - 1);
            }
        }
    }

    public static void main(String[] args) {
        Permutations permutations = new Permutations();
        int[] nums = {1, 2, 3};
        System.out.println(permutations.permute(nums));
    }
}
#include <vector>
#include <algorithm>
#include <iostream>

std::vector<std::vector<int>> permute(std::vector<int>& nums) {
    std::vector<std::vector<int>> result;
    std::sort(nums.begin(), nums.end());
    do {
        result.push_back(nums);
    } while (std::next_permutation(nums.begin(), nums.end()));
    return result;
}

int main() {
    std::vector<int> nums = {1, 2, 3};
    std::vector<std::vector<int>> result = permute(nums);
    for (const auto& permutation : result) {
        for (int num : permutation) {
            std::cout << num << " ";
        }
        std::cout << "\n";
    }
    return 0;
}
function permute(nums) {
    const result = [];
    const backtrack = (path) => {
        if (path.length === nums.length) {
            result.push([...path]);
            return;
        }
        for (const num of nums) {
            if (!path.includes(num)) {
                path.push(num);
                backtrack(path);
                path.pop();
            }
        }
    };
    backtrack([]);
    return result;
}

console.log(permute([1, 2, 3]));
#include <stdio.h>

void swap(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

void backtrack(int* nums, int numsSize, int start, int** result, int* returnSize, int* returnColumnSizes) {
    if (start == numsSize) {
        result[*returnSize] = (int*)malloc(sizeof(int) * numsSize);
        for (int i = 0; i < numsSize; i++) {
            result[*returnSize][i] = nums[i];
        }
        returnColumnSizes[*returnSize] = numsSize;
        (*returnSize)++;
    } else {
        for (int i = start; i < numsSize; i++) {
            swap(&nums[start], &nums[i]);
            backtrack(nums, numsSize, start + 1, result, returnSize, returnColumnSizes);
            swap(&nums[start], &nums[i]);
        }
    }
}

int** permute(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {
    int factorial = 1;
    for (int i = 2; i <= numsSize; i++) {
        factorial *= i;
    }
    int** result = (int**)malloc(sizeof(int*) * factorial);
    *returnColumnSizes = (int*)malloc(sizeof(int) * factorial);
    *returnSize = 0;
    backtrack(nums, numsSize, 0, result, returnSize, *returnColumnSizes);
    return result;
}

int main() {
    int nums[] = {1, 2, 3};
    int returnSize;
    int* returnColumnSizes;
    int** result = permute(nums, 3, &returnSize, &returnColumnSizes);
    for (int i = 0; i < returnSize; i++) {
        for (int j = 0; j < returnColumnSizes[i]; j++) {
            printf("%d ", result[i][j]);
        }
        printf("\n");
    }
    for (int i = 0; i < returnSize; i++) {
        free(result[i]);
    }
    free(result);
    free(returnColumnSizes);
    return 0;
}
using System;
using System.Collections.Generic;

public class Permutations {
    public IList<IList<int>> Permute(int[] nums) {
        var result = new List<IList<int>>();
        Backtrack(nums, new List<int>(), result);
        return result;
    }

    private void Backtrack(int[] nums, List<int> tempList, List<IList<int>> result) {
        if (tempList.Count == nums.Length) {
            result.Add(new List<int>(tempList));
        } else {
            for (int i = 0; i < nums.Length; i++) {
                if (tempList.Contains(nums[i])) continue;
                tempList.Add(nums[i]);
                Backtrack(nums, tempList, result);
                tempList.RemoveAt(tempList.Count - 1);
            }
        }
    }

    public static void Main(string[] args) {
        var permutations = new Permutations();
        int[] nums = {1, 2, 3};
        var result = permutations.Permute(nums);
        foreach (var perm in result) {
            Console.WriteLine(string.Join(", ", perm));
        }
    }
}

This Python implementation uses a recursive backtracking approach to generate the permutations. It swaps the elements to fix elements at each recursive level and then backtracks to get back to the previous state.

Complexity

Time Complexity: O(n * n!) as all permutations are generated and stored.
Space Complexity: O(n!) is required to store all permutations, and O(n) for recursion call stack.

Try this approach in the editor

Approach 2: Iterative Permutation Generation

An alternative iterative approach utilizes a queue to generate permutations level by level by inserting each number at every possible position within every possible permutation.

from itertools import permutations

def permute(nums):
    return list(permutations(nums))

print(permute([1, 2, 3]))
import java.util.ArrayList;
import java.util.List;
import java.util.Arrays;

public class Permutations {
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> results = new ArrayList<>();
        Arrays.sort(nums);
        do {
            List<Integer> current = new ArrayList<>();
            for (int num : nums) {
                current.add(num);
            }
            results.add(new ArrayList<>(current));
        } while (nextPermutation(nums));
        return results;
    }

    private boolean nextPermutation(int[] nums) {
        int i = nums.length - 2;
        while (i >= 0 && nums[i] >= nums[i + 1]) i--;
        if (i < 0) return false;
        int j = nums.length - 1;
        while (nums[j] <= nums[i]) j--;
        swap(nums, i, j);
        reverse(nums, i + 1);
        return true;
    }

    private void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }

    private void reverse(int[] nums, int start) {
        int i = start, j = nums.length - 1;
        while (i < j) swap(nums, i++, j--);
    }

    public static void main(String[] args) {
        Permutations perm = new Permutations();
        int[] nums = {1, 2, 3};
        List<List<Integer>> results = perm.permute(nums);
        System.out.println(results);
    }
}
#include <vector>
#include <iostream>
#include <algorithm>

std::vector<std::vector<int>> permute(std::vector<int>& nums) {
    std::vector<std::vector<int>> result;
    std::sort(nums.begin(), nums.end());
    do {
        result.push_back(nums);
    } while (std::next_permutation(nums.begin(), nums.end()));
    return result;
}

int main() {
    std::vector<int> nums = {1, 2, 3};
    std::vector<std::vector<int>> result = permute(nums);
    for (const auto& perm : result) {
        for (int num : perm) {
            std::cout << num << " ";
        }
        std::cout << '\n';
    }
    return 0;
}
function permute(nums) {
    const res = [];
    const nextPermutation = (arr) => {
        let i = arr.length - 2;
        while (i >= 0 && arr[i] >= arr[i + 1]) i--;
        if (i < 0) return false;
        let j = arr.length - 1;
        while (arr[j] <= arr[i]) j--;
        [arr[i], arr[j]] = [arr[j], arr[i]];
        arr = arr.slice(0, i + 1).concat(arr.slice(i + 1).reverse());
        return arr;
    };

    nums.sort((a, b) => a - b);
    res.push([...nums]);
    while (nums = nextPermutation(nums.slice())) {
        res.push([...nums]);
    }
    return res;
}

console.log(permute([1, 2, 3]));
#include <stdio.h>
#include <stdlib.h>

void swap(int* a, int* b) {
    int temp = *a;
    *a = *b;
    *b = temp;
}

int** permute(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {
    int factorial = 1;
    for (int i = 2; i <= numsSize; i++) {
        factorial *= i;
    }
    int** result = (int**)malloc(sizeof(int*) * factorial);
    *returnColumnSizes = (int*)malloc(sizeof(int) * factorial);
    *returnSize = 0;
    int* current = (int*)malloc(sizeof(int) * numsSize);

    for (int i = 0; i < numsSize; i++) {
        current[i] = nums[i];
    }

    for (int i = 0; i < factorial; i++) {
        result[i] = (int*)malloc(sizeof(int) * numsSize);
        for (int j = 0; j < numsSize; j++) {
            result[i][j] = current[j];
        }
        (*returnColumnSizes)[i] = numsSize;

        int j = numsSize - 1;
        while (j > 0 && current[j - 1] >= current[j]) {
            j--;
        }
        if (j > 0) {
            int swapIndex = numsSize - 1;
            while (current[swapIndex] <= current[j - 1]) {
                swapIndex--;
            }
            swap(&current[j - 1], &current[swapIndex]);
        }
        for (int k = j, l = numsSize - 1; k < l; k++, l--) {
            swap(&current[k], &current[l]);
        }
    }
    free(current);
    return result;
}

int main() {
    int nums[] = {1, 2, 3};
    int returnSize;
    int* returnColumnSizes;
    int** result = permute(nums, 3, &returnSize, &returnColumnSizes);
    for (int i = 0; i < returnSize; i++) {
        for (int j = 0; j < returnColumnSizes[i]; j++) {
            printf("%d ", result[i][j]);
        }
        printf("\n");
    }
    for (int i = 0; i < returnSize; i++) {
        free(result[i]);
    }
    free(result);
    free(returnColumnSizes);
    return 0;
}
using System;
using System.Collections.Generic;

public class Permutations {
    public IList<IList<int>> Permute(int[] nums) {
        List<IList<int>> result = new List<IList<int>>();
        Array.Sort(nums);
        do {
            result.Add(new List<int>(nums));
        } while (NextPermutation(nums));
        return result;
    }

    private bool NextPermutation(int[] nums) {
        int i = nums.Length - 2;
        while (i >= 0 && nums[i] >= nums[i + 1]) i--;
        if (i < 0) return false;
        int j = nums.Length - 1;
        while (nums[j] <= nums[i]) j--;
        Swap(nums, i, j);
        Array.Reverse(nums, i + 1, nums.Length - i - 1);
        return true;
    }

    private void Swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }

    public static void Main(string[] args) {
        var permutations = new Permutations();
        int[] nums = {1, 2, 3};
        var result = permutations.Permute(nums);
        foreach (var perm in result) {
            Console.WriteLine(string.Join(", ", perm));
        }
    }
}

This Python solution uses the itertools.permutations function that directly generates permutations using combinatorial generation, simplifying implementation.

Complexity

Time Complexity: O(n * n!) inherently due to combination generation.
Space Complexity: O(n!) for storing final permutations.

Try this approach in the editor

Approach 3: DFS (Backtracking)

We design a function dfs(i) to represent that the first i positions have been filled, and now we need to fill the i+1 position. We enumerate all possible numbers, if this number has not been filled, we fill in this number, and then continue to fill the next position, until all positions are filled.

The time complexity is O(n times n!), where n is the length of the array. There are n! permutations in total, and each permutation takes O(n) time to construct.

Similar problems:

function permute(nums: number[]): number[][] {
    const n = nums.length;
    const ans: number[][] = [];
    const vis: boolean[] = Array(n).fill(false);
    const t: number[] = Array(n).fill(0);
    const dfs = (i: number) => {
        if (i >= n) {
            ans.push(t.slice());
            return;
        }
        for (let j = 0; j < n; ++j) {
            if (!vis[j]) {
                vis[j] = true;
                t[i] = nums[j];
                dfs(i + 1);
                vis[j] = false;
            }
        }
    };
    dfs(0);
    return ans;
}
func permute(nums []int) (ans [][]int) {
	n := len(nums)
	t := make([]int, n)
	vis := make([]bool, n)
	var dfs func(int)
	dfs = func(i int) {
		if i == n {
			ans = append(ans, slices.Clone(t))
			return
		}
		for j, x := range nums {
			if !vis[j] {
				vis[j] = true
				t[i] = x
				dfs(i + 1)
				vis[j] = false
			}
		}
	}
	dfs(0)
	return
}
impl Solution {
    pub fn permute(nums: Vec<i32>) -> Vec<Vec<i32>> {
        let n = nums.len();
        let mut ans = Vec::new();
        let mut t = vec![0; n];
        let mut vis = vec![false; n];
        fn dfs(
            nums: &Vec<i32>,
            n: usize,
            t: &mut Vec<i32>,
            vis: &mut Vec<bool>,
            ans: &mut Vec<Vec<i32>>,
            i: usize
        ) {
            if i == n {
                ans.push(t.clone());
                return;
            }
            for j in 0..n {
                if !vis[j] {
                    vis[j] = true;
                    t[i] = nums[j];
                    dfs(nums, n, t, vis, ans, i + 1);
                    vis[j] = false;
                }
            }
        }
        dfs(&nums, n, &mut t, &mut vis, &mut ans, 0);
        ans
    }
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Backtracking Approach

Time Complexity: O(n * n!) as all permutations are generated and stored.
Space Complexity: O(n!) is required to store all permutations, and O(n) for recursion call stack.

Iterative Permutation Generation

Time Complexity: O(n * n!) inherently due to combination generation.
Space Complexity: O(n!) for storing final permutations.

DFS (Backtracking)–

Complexity analysis

ApproachTimeSpaceWhen to Use
BacktrackingO(n! * n)O(n)Standard interview approach for generating permutations using recursion
Iterative Permutation GenerationO(n! * n)O(n!)When recursion is avoided or when building permutations iteratively

Frequently asked questions

Is Permutations easy or hard?

Permutations is considered a medium difficulty problem. The implementation requires understanding recursion and backtracking, but the core idea is straightforward once you visualize choosing elements and undoing choices after each recursive call.

Permutations Python/Java solution

Python and Java solutions typically implement recursive backtracking. A list stores the current permutation, a boolean array tracks used numbers, and when the permutation length reaches n it gets copied into the result list.

How to solve Permutations in O(n)?

Generating every permutation cannot be done in O(n) because the output itself contains n! permutations. The optimal approach is O(n! * n) using backtracking or iterative insertion. The factorial growth comes from the number of possible arrangements.

What is the best approach for Permutations?

Backtracking is the most common and interview-preferred approach. It builds permutations step by step, recursively selecting unused elements and backtracking after exploring each branch. This guarantees all n! permutations are generated with O(n! * n) time complexity.

Is Permutations asked at Google/Amazon/Meta?

Permutation generation problems frequently appear in interviews at companies like Amazon, Google, and Meta. They test recursion, backtracking, and the ability to explore combinatorial search spaces efficiently.

What data structure is used in Permutations?

Most solutions use arrays or lists to store the current permutation and a boolean array or set to track used elements. Recursive backtracking relies on the call stack to explore choices and revert state after each branch.

What is the time complexity of Permutations?

Generating all permutations requires O(n! * n) time. There are n! possible permutations of n elements, and copying each permutation into the result list costs O(n). Any algorithm that lists all permutations will have at least factorial complexity.

Comments

Now write it yourselfClose this page and solve Permutations in the editor, without looking.
Practise Permutations