Skip to content
DSAPrep

    ↑↓ to move · Enter to open · Esc to close

    Permutations

    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.
    View original on LeetCode ↗

    Unlike subsets, order matters here, so we cannot just walk forward through indices — every position can take any not-yet-used number.

    Swap-Based Backtracking (In-Place)

    Time O(n · n!)Space O(n)

    Fix the element at index i by swapping in each candidate from the remaining suffix, recurse on i + 1, then swap back. This avoids a separate “used” structure but mutates the input array during recursion.

    class Solution:
    def permute(self, nums: list[int]) -> list[list[int]]:
    result = []
    def backtrack(i):
    if i == len(nums):
    result.append(nums[:])
    return
    for j in range(i, len(nums)):
    nums[i], nums[j] = nums[j], nums[i]
    backtrack(i + 1)
    nums[i], nums[j] = nums[j], nums[i] # undo the swap
    backtrack(0)
    return result

    Same O(n · n!) time and O(n) recursion depth as the approach below — this is really a style choice (swap vs. explicit used-set), not a performance win. It is slightly less intuitive to trace since the array itself changes shape mid-recursion.

    Backtracking with a Used-Set

    OptimalTime O(n · n!)Space O(n)

    Build a path one slot at a time. At each step, try every number not already in path (tracked via a used array), append it, recurse, then remove it. A permutation is complete once path reaches length n.

    class Solution:
    def permute(self, nums: list[int]) -> list[list[int]]:
    n = len(nums)
    result = []
    path = []
    used = [False] * n
    def backtrack():
    if len(path) == n:
    result.append(path[:])
    return
    for i in range(n):
    if used[i]:
    continue
    used[i] = True
    path.append(nums[i])
    backtrack()
    path.pop()
    used[i] = False
    backtrack()
    return result

    Watch how choosing an index flips its used flag and appends to the path, and how backtracking frees that index again so a sibling branch can reuse it. Tracing the second example nums = [0,1]:

    Input — indigo means the index is in the current path

    0free
    1free

    Path — one fixed slot per input position

    ?
    ?

    Results — 0 of 2

    1 / 12
    currentcomparingresult

    Start with an empty path and every index free. The loop tries each unused index, so index 0 is attempted first.

    Complexity: there are n! complete permutations, and building each one costs O(n) (one append per level plus the final copy) → O(n · n!) time. The used array and path/recursion depth are all O(n) → O(n) auxiliary space.

    More Backtracking practice