Post

Backtracking - Permutations II

All diagrams presented herein are original creations, meticulously designed to enhance comprehension and recall. Crafting these aids required considerable effort, and I kindly request attribution if this content is reused elsewhere.

Difficulty : Medium

DFS, Backtracking, Map

Problem

Given a collection of numbers, nums, that might contain duplicates, return all possible unique permutations in any order.

Example 1:

1
2
3
4
5
Input: nums = [1,1,2]
Output:
[[1,1,2],
 [1,2,1],
 [2,1,1]]

Example 2:

1
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

This is very similar to the previous Permutations problem however like we used almost the same solution for Subset II from Subset, we won’t be able to do the same. Here in order to avoid the duplicates, we will transform the input list to a map object and use that to traverse the dfs() for negating sequences.

1
2
3
nums_map=collections.defaultdict(int)
for n in nums:
  nums_map[n]+=1
1
2
3
4
{
	1: 2, 
	2: 1
}

In the dfs() function, the terminating/base condition is similar to what we have used in the Subset problem. Like in the Subset problem we will define permutation_arr outside, though it can also be passed as an argument in the dfs() function.

1
2
3
4
5
6
permutation_arr = []
output=[]
def dfs():
  if len(permutation_arr) == len(nums):
    output.append(permutation_arr.copy())
    return

Now we will loop through each unique element in the nums_map. If the number in the nums_map is more than 0 then we know we can call dfs() again. The idea is to keep subtracting the value from the nums_map however the loop will only be for len(nums_map.keys()). This will ensure number of unique combinations are equal to number of unique elements in the input nums array.

1
2
3
  for key in nums_map:
    if nums_map[key] >0 :
    ...

Now add each key to the permutation_arr , decrement the counter in the nums_map then run dfs(). Once its completed perform the backtracking.

1
2
3
4
5
6
7
8
9
  for key in nums_map:
    if nums_map[key] >0 :
      permutation_arr.append(key)
      nums_map[key]-=1
    
      dfs()
    
      nums_map[key]+=1
      permutation_arr.pop()

Finally invoke dfs() and return the output.

1
2
dfs()
return output

Here is the visualization.

image-20240514012916014

Final Code

Here is the full code.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
def permutations_ii(nums):
    output = []
    permutation_arr = []
    nums_map = collections.defaultdict(int)
    for n in nums:
        nums_map[n] += 1

    def dfs():
        if len(permutation_arr) == len(nums):
            output.append(permutation_arr.copy())
            return

        for key in nums_map:
            if nums_map[key] > 0:
                permutation_arr.append(key)
                nums_map[key] -= 1

                dfs()

                nums_map[key] += 1
                permutation_arr.pop()

    dfs()
    return output
This post is licensed under CC BY 4.0 by the author.