Given a collection of numbers, nums
, that might contain duplicates, return all possible unique permutations in any order.
Example 1:
Input: nums = [1,1,2] Output: [[1,1,2], [1,2,1], [2,1,1]]
Example 2:
Input: nums = [1,2,3] Output: [[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,2,1]]
Constraints:
1 <= nums.length <= 8
-10 <= nums[i] <= 10
This problem asks to generate all unique permutations of a given array containing potentially duplicate numbers. The solution uses a backtracking approach enhanced with sorting and duplicate handling.
Approach:
Sorting: The input array nums
is first sorted. This crucial step groups identical numbers together, simplifying duplicate detection during permutation generation.
Backtracking (DFS): A depth-first search (DFS) function, dfs(i)
, recursively explores all possible permutations. i
represents the index of the element currently being placed in the permutation.
Base Case: If i
equals the length of nums
, a complete permutation (t
) has been formed. This permutation is added to the result list ans
.
Recursive Step: The function iterates through nums
. For each element nums[j]
, it checks two conditions:
vis[j]
: This boolean array tracks whether the element at index j
has already been used in the current permutation. It prevents revisiting elements within a single permutation.(j and nums[j] == nums[j - 1] and not vis[j - 1])
: This condition prevents duplicates. If the current element is identical to the previous one and the previous one hasn't been used yet, it skips the current element to avoid generating redundant permutations.If both conditions are false (the element is available), it's added to the current permutation t
, marked as used (vis[j] = true
), and the dfs
function recursively calls itself to fill the next position (dfs(i + 1)
). After the recursive call, vis[j]
is set back to false
to allow the element to be used in other permutations.
Time Complexity: O(n * n!)
Space Complexity: O(n)
vis
array and t
array both take O(n) space.Code Examples (Python, Java, C++, Go, TypeScript, Rust, JavaScript, C#):
The provided code snippets demonstrate the algorithm in several programming languages. They all follow the same logic: sorting, backtracking with duplicate handling, and the use of a boolean array to track visited elements. Note that minor syntactic differences exist between languages, but the core algorithm remains the same.
Example Usage (Python):
solution = Solution()
nums = [1, 1, 2]
result = solution.permuteUnique(nums)
print(result) # Output: [[1, 1, 2], [1, 2, 1], [2, 1, 1]]
This detailed explanation clarifies the algorithm, complexities, and code implementation of the solution for generating unique permutations with duplicates. The use of sorting and careful duplicate checking ensures efficient and correct generation of all unique permutations.