Problem
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]]
Solution
Method 1 - Backtracking with frequency map
This is similar to Permutations of Array 1. But the normal decision tree will not work.
So, instead of array, we can use hashmap of frequency. This is our frequency map:
freq<num,count> = {1: 1, 2:1}
Now, decision tree will have 2 keys - [1, 2]
. On the left side, we choose one 1
and one 2
.
Final decision tree:
Code
Java
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> ans = new ArrayList<>();
List<Integer> subAns = new ArrayList<>();
// frequency map
Map<Integer, Long> countMap = Arrays.stream(nums).boxed().
collect(Collectors.groupingBy(Integer::intValue, Collectors.counting()));
dfs(nums.length, countMap, subAns, ans);
return ans;
}
public void dfs(int numsLength, Map<Integer, Long> countMap, List<Integer> subAns, List<List<Integer>> ans) {
if (subAns.size() == numsLength) {
ans.add(new ArrayList<>(subAns));
return;
}
for(int num: countMap.keySet()){
if(countMap.get(num) > 0){
subAns.add(num);
countMap.put(num, countMap.get(num)-1);
dfs(numsLength, countMap, subAns, ans);
// undo
countMap.put(num, countMap.get(num)+1);
subAns.remove(subAns.size()-1);
}
}
}
Complexity
- ⏰ Time complexity:
O(n*2^n)
- 🧺 Space complexity:
O(n)
assuming recursion stack
Method 2 - Backtracking with visited array and sorting
Code
Java
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> list = new ArrayList<>();
Arrays.sort(nums);
backtrack(list, new ArrayList<>(), nums, new boolean[nums.length]);
return list;
}
private void backtrack(List<List<Integer>> list, List<Integer> tempList, int[] nums, boolean[] used) {
if (tempList.size() == nums.length) {
list.add(new ArrayList<>(tempList));
return;
}
for (int i = 0; i<nums.length; i++) {
if (used[i] || i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) {
continue;
}
used[i] = true;
tempList.add(nums[i]);
backtrack(list, tempList, nums, used);
used[i] = false;
tempList.remove(tempList.size() - 1);
}
}