Permutations II

Backtracking with a "use-leftmost-unused-duplicate" tie-breaker — sort, then skip a value if its previous copy is unused.

Medium
Time O(n * n!) Space O(n)
LeetCode
4 min read
backtracking recursion

Problem#

Given an array that may contain duplicates, return all unique permutations.

Examples#

  • [1,1,2][[1,1,2],[1,2,1],[2,1,1]].
  • [1,2,3] → all 6 perms.

Constraints#

  • 1 <= nums.length <= 8.

Approach#

Sort. Backtrack with a used[] flag per position. For each candidate at the current step, skip duplicates whose previous-equal-copy is unused — this canonical-choice rule produces each unique permutation exactly once.

Solution#

Permutations II
class Solution {
vector<vector<int>> ans;
vector<int> cur, used;
vector<int> nums;
void dfs() {
if (cur.size() == nums.size()) { ans.push_back(cur); return; }
for (int i = 0; i < (int)nums.size(); ++i) {
if (used[i]) continue;
if (i > 0 && nums[i] == nums[i-1] && !used[i-1]) continue;
used[i] = 1;
cur.push_back(nums[i]);
dfs();
cur.pop_back();
used[i] = 0;
}
}
public:
vector<vector<int>> permuteUnique(vector<int>& nums_) {
nums = nums_;
sort(nums.begin(), nums.end());
used.assign(nums.size(), 0);
dfs();
return ans;
}
};

Editorial#

After sorting, equal values are adjacent. The rule “skip a duplicate whose previous copy is still unused” enforces a fixed canonical order for the duplicate copies’ usage, so the same permutation can’t be reached two ways.

Complexity#

  • Time: O(n * n!) in the worst case.
  • Space: O(n) recursion.

Concept revision#

Search ESC

Keyboard shortcuts

Shortcuts are disabled while typing in inputs.