# Permutations problem Generating permutations is a classic application of backtracking. Given a collection, such as an array or a string, the task is to find every possible ordering of its elements. The table below gives several input arrays and all their permutations.

Table   Examples of permutations

| Input array | All permutations | | :---------- | :----------------------------------------------------------------- | | $[1]$ | $[1]$ | | $[1, 2]$ | $[1, 2], [2, 1]$ | | $[1, 2, 3]$ | $[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]$ | ## Distinct elements !!! question Given an integer array with no duplicate elements, return all possible permutations. From a backtracking perspective, **we can view a permutation as the result of a sequence of choices**. For input $[1, 2, 3]$, choosing $1$, then $3$, then $2$ produces $[1, 3, 2]$. Backtracking undoes a choice so that other choices can be tried. In the code, `choices` contains all the input elements, and `state` contains the elements chosen so far. Each element may be chosen only once, **so every element in `state` must be unique**. As shown in the figure below, we can expand the search into a recursion tree, where each node represents the current `state`. Starting from the root, three rounds of choices lead to a leaf, and each leaf corresponds to one permutation. ![Recursion tree for permutations](permutations_problem.assets/permutations_i.png) ### Pruning repeated selections To ensure that each element is chosen only once, introduce a Boolean array `selected`, where `selected[i]` indicates whether `choices[i]` has been chosen. Use it for the following pruning steps. - After choosing `choices[i]`, set `selected[i]` to $\text{True}$ to mark it as selected. - When iterating over `choices`, skip all selected elements, pruning their branches. As shown in the figure below, if we choose 1 first, 3 second, and 2 third, we must prune the branch for 1 in the second round and the branches for 1 and 3 in the third round. ![Example of pruning permutations](permutations_problem.assets/permutations_i_pruning.png) This pruning reduces the search space from $O(n^n)$ to $O(n!)$. ### Code implementation With these details established, we can fill in the backtracking template. To keep the code short, we inline the template's helper functions into `backtrack()`: ```src [file]{permutations_i}-[class]{}-[func]{permutations_i} ``` ## Duplicate elements !!! question Given an integer array that **may contain duplicate elements**, return all distinct permutations. Suppose the input is $[1, 1, 2]$. To distinguish the two occurrences of $1$, denote the second $1$ by $\hat{1}$. As shown in the figure below, half the permutations generated by the previous method are duplicates. ![Duplicate permutations](permutations_problem.assets/permutations_ii.png) How can we remove these duplicates? A straightforward approach is to use a hash set to deduplicate the results. However, this is inelegant: **branches that generate duplicate permutations are unnecessary and should be identified and pruned in advance**, improving efficiency. ### Pruning equal elements In the figure below, choosing $1$ or $\hat{1}$ in the first round is equivalent: every permutation produced under one choice is duplicated under the other. We should therefore prune $\hat{1}$. Similarly, after choosing $2$ in the first round, choosing either $1$ or $\hat{1}$ in the second produces duplicate branches. Prune the second-round choice of $\hat{1}$ as well. In essence, **within any one round of choices, we want to try only one of the elements with the same value**. ![Pruning duplicate permutations](permutations_problem.assets/permutations_ii_pruning.png) ### Code implementation Building on the previous solution, create a hash set `duplicated` in each round to record the values already tried in that round and prune repeated values: ```src [file]{permutations_ii}-[class]{}-[func]{permutations_ii} ``` If all elements are distinct, $n$ elements have $n!$ permutations, where the exclamation mark denotes factorial. Recording each result requires copying a list of length $n$, taking $O(n)$ time. **The time complexity is therefore $O(n!n)$**. The maximum recursion depth is $n$, requiring $O(n)$ space for stack frames. The array `selected` uses $O(n)$ space. At most $n$ `duplicated` sets exist at once, using $O(n^2)$ space. **The space complexity is therefore $O(n^2)$**. ### Comparing the two pruning methods Although both `selected` and `duplicated` are used for pruning, they serve different purposes. - **Pruning repeated selections**: There is only one `selected` array throughout the search. It records which elements are in the current state, preventing the same element from appearing twice in `state`. - **Pruning equal elements**: Each round of choices (each call to `backtrack`) has its own `duplicated` set. It records the values already chosen in that round's `for` loop, ensuring that equal elements are tried only once in that round. The figure below shows the scope of each pruning condition. Each node represents a choice, and the nodes along a path from root to leaf form a permutation. ![Scope of the two pruning conditions](permutations_problem.assets/permutations_ii_pruning_summary.png)