medium Permutations II
Problem Statement
Given a list of numbers nums that might have duplicates, return all unique arrangements of the numbers in any order.
Examples
Example 1:
- Input: nums = [1, 2, 2]
- Output: [[1,2,2],[2,1,2],[2,2,1]]
- Explanation: There are a total of 6 permutations of [1, 2, 2] list but only 3 are unique.
Example 2:
- Input: nums = [2, 2, 3]
- Output: [[2,2,3],[2,3,2],[3,2,2]]
- Explanation: All unique permutations of the list [2, 2, 3] are shown above.
Example 3:
- Input: nums = [1, 2, 2, 3]
- Output: [[1,2,2,3],[1,2,3,2],[1,3,2,2],[2,1,2,3],[2,1,3,2],[2,2,1,3],[2,2,3,1],[2,3,1,2],[2,3,2,1],[3,1,2,2],[3,2,1,2],[3,2,2,1]]
- Explanation: All unique permutations of the list [1, 2, 2, 3] are shown above.
Constraints:
- 1 <= nums.length <= 8
- -10 <= nums[i] <= 10
Try it yourself
Try solving this question here:
✅ Solution Permutations II
Problem Statement
Given a list of numbers nums that might have duplicates, return all unique arrangements of the numbers in any order.
Examples
Example 1:
- Input: nums = [1, 2, 2]
- Output: [[1,2,2],[2,1,2],[2,2,1]]
- Explanation: There are a total of 6 permutations of [1, 2, 2] list but only 3 are unique.
Example 2:
- Input: nums = [2, 2, 3]
- Output: [[2,2,3],[2,3,2],[3,2,2]]
- Explanation: All unique permutations of the list [2, 2, 3] are shown above.
Example 3:
- Input: nums = [1, 2, 2, 3]
- Output: [[1,2,2,3],[1,2,3,2],[1,3,2,2],[2,1,2,3],[2,1,3,2],[2,2,1,3],[2,2,3,1],[2,3,1,2],[2,3,2,1],[3,1,2,2],[3,2,1,2],[3,2,2,1]]
- Explanation: All unique permutations of the list [1, 2, 2, 3] are shown above.
Constraints:
- 1 <= nums.length <= 8
- -10 <= nums[i] <= 10
Solution
To solve this problem, we need to generate all possible permutations of the input list while ensuring that we do not include duplicate permutations. We can achieve this by sorting the list first, which helps in skipping duplicate numbers during the permutation process. Using a backtracking approach, we build permutations incrementally by adding one number at a time and ensuring that each number is not used more than once at a specific position. By marking numbers that have been used in the current recursive call, we can avoid duplicates effectively.
This approach works well because it systematically explores all potential permutations while skipping over duplicate entries. By leveraging a sorted list and a used array, we ensure each permutation is unique and all possible permutations are considered.
Step-by-Step Algorithm
- Sort the input array
numsto handle duplicates easily. - Initialize an empty list
resultto store all unique permutations. - Define a helper function
backtrackthat takes the current permutationtempList, a boolean arrayusedto track used elements, andnums. - Check if the length of
tempListis equal to the length ofnums:- If true, add a copy of
tempListtoresult. - If false, proceed to the next step.
- If true, add a copy of
- Iterate over each element in
nums:- Skip elements that are already used or duplicate elements that are not used in the current recursive call.
- Mark the current element as used.
- Add the current element to
tempList. - Recursively call
backtrackwith the updatedtempListandusedarray. - Backtrack by unmarking the current element and removing it from
tempList.
- Call the
backtrackfunction with an emptytempListand ausedarray ofFalsevalues. - Return the
resultlist containing all unique permutations.
Algorithm Walkthrough
Using the input nums = [1, 2, 2]:
- Sort the array: The sorted array remains
[1, 2, 2]. - Initialize
result:result = []. - Call
backtrackwithtempList = []andused = [False, False, False].
First Level:
- Iterate over
nums:- i = 0:
nums[0] = 1, not used. Add totempListand mark as used.tempList = [1],used = [True, False, False].- Call
backtrackwith updatedtempListandused.
- i = 0:
Second Level:
- Iterate over
nums:- i = 0:
nums[0] = 1, already used. Skip.
- i = 1:
nums[1] = 2, not used. Add totempListand mark as used.tempList = [1, 2],used = [True, True, False].- Call
backtrackwith updatedtempListandused.
- i = 0:
Third Level:
- Iterate over
nums:- i = 0:
nums[0] = 1, already used. Skip.
- i = 1:
nums[1] = 2, already used. Skip.
- i = 2:
nums[2] = 2, not used. Add totempListand mark as used.tempList = [1, 2, 2],used = [True, True, True].- Call
backtrackwith updatedtempListandused.
- i = 0:
Fourth Level:
tempListlength equalsnumslength.- Add
[1, 2, 2]toresult. result = [[1, 2, 2]].
- Add
Backtrack:
- Unmark
nums[2]and remove fromtempList.tempList = [1, 2],used = [True, True, False].
- Return to the previous level.
Backtrack:
- Unmark
nums[1]and remove fromtempList.tempList = [1, 2],used = [True, False, True].
- Return to the previous level.
Third Level:
- Continue iteration:
- i = 2:
- Already processed. Skip.
- i = 2:
Backtrack:
- Unmark
nums[2]and remove fromtempList.tempList = [1],used = [True, False, False].
- Return to the previous level.
First Level:
- Continue iteration:
- i = 1:
nums[1] = 2, not used. Add totempListand mark as used.tempList = [2],used = [False, True, False].- Call
backtrackwith updatedtempListandused.
- i = 1:
Second Level:
- Iterate over
nums:- i = 0:
nums[0] = 1, not used. Add totempListand mark as used.tempList = [2, 1],used = [True, True, False].- Call
backtrackwith updatedtempListandused.
- i = 0:
Third Level:
- Iterate over
nums:- i = 0:
- Already used. Skip.
- i = 1:
- Already used. Skip.
- i = 2:
nums[2] = 2, not used. Add totempListand mark as used.tempList = [2, 1, 2],used = [True, True, True].- Call
backtrackwith updatedtempListandused.
- i = 0:
Fourth Level:
tempListlength equalsnumslength.- Add
[2, 1, 2]toresult. result = [[1, 2, 2], [2, 1, 2]].
- Add
Backtrack:
- Unmark
nums[2]and remove fromtempList.tempList = [2, 1],used = [True, True, False].
- Return to the previous level.
Third Level:
- Continue iteration:
- i = 2:
- Already processed. Skip.
- i = 2:
Backtrack:
- Unmark
nums[0]and remove fromtempList.tempList = [2],used = [False, True, False].
- Return to the previous level.
Second Level:
- Continue iteration:
- i = 1:
- Already processed. Skip.
- i = 2:
nums[2] = 2, not used. Add totempListand mark as used.tempList = [2, 2],used = [False, True, True].- Call
backtrackwith updatedtempListandused.
- i = 1:
Third Level:
- Iterate over
nums:- i = 0:
nums[0] = 1, not used. Add totempListand mark as used.tempList = [2, 2, 1],used = [True, True, True].- Call
backtrackwith updatedtempListandused.
- i = 0:
Fourth Level:
tempListlength equalsnumslength.- Add
[2, 2, 1]toresult. result = [[1, 2, 2], [2, 1, 2], [2, 2, 1]].
- Add
Return Result:
- All permutations of the
[1, 2, 2]list are[[1, 2, 2], [2, 1, 2], [2, 2, 1]].
Code
import java.util.*;
public class Solution {
// Method to return all unique permutations
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
Arrays.sort(nums); // Sort the numbers to handle duplicates
backtrack(result, new ArrayList<>(), nums, new boolean[nums.length]);
return result;
}
// Helper method for backtracking
private void backtrack(
List<List<Integer>> result,
List<Integer> tempList,
int[] nums,
boolean[] used
) {
if (tempList.size() == nums.length) {
result.add(new ArrayList<>(tempList)); // Add the current permutation to the result
} else {
for (int i = 0; i < nums.length; i++) {
if (
used[i] || (i > 0 && nums[i] == nums[i - 1] && !used[i - 1])
) continue; // Skip duplicates
used[i] = true; // Mark the number as used
tempList.add(nums[i]); // Add number to the current permutation
backtrack(result, tempList, nums, used); // Recur with the next number
used[i] = false; // Unmark the number
tempList.remove(tempList.size() - 1); // Remove the number from the current permutation
}
}
}
public static void main(String[] args) {
Solution sol = new Solution();
int[][] inputs = { { 1, 2, 2 }, { 2, 2, 3 }, { 1, 2, 2, 3 } };
for (int[] input : inputs) {
List<List<Integer>> result = sol.permuteUnique(input);
System.out.println("Input: " + Arrays.toString(input));
System.out.println("Permutations: " + result);
}
}
}
Complexity Analysis
Time Complexity
The time complexity of generating all permutations is
- There are n! permutations in total.
- For each permutation, it takes
time to build and store it.
Additionally, sorting the array initially takes
Space Complexity
The space complexity is
- We store all n! permutations, each of length n.
- The recursion stack can go as deep as n, and we maintain a temporary list of length n and a used array of length n.
Hence, the overall space complexity is
🤖 Don't fully get this? Learn it with Claude
Stuck on Permutations II? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.
Progressively stronger hints — you still solve it.
I'm working on the problem **Permutations II** (DSA). Give me a HINT LADDER: start with the tiniest nudge, then wait. Only reveal the next, stronger hint when I ask. Do NOT show the full solution unless I type 'show solution'. Keep me doing the thinking. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
See the technique, not just code.
Explain the optimal approach to **Permutations II** with a VISUAL walkthrough: trace it on a small concrete example using ASCII art / a step-by-step diagram, narrate what changes each step, then give time & space complexity with a one-line derivation. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Catch bugs, edge cases, sub-optimality.
I'll paste my solution to **Permutations II**. Review it for correctness, missed edge cases, and time/space complexity, then coach me toward the optimal — don't just rewrite it. Ask me to paste my code now. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Lock in recognition with look-alikes.
Give me 2 problems that use the SAME underlying pattern as **Permutations II**. For each, let me attempt first, then review my answer and name the trigger signal that reveals the pattern. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.