LC46. Permutations

Given a collection of distinct integers, return all possible permutations.

Input: [1,2,3] Output: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]

When we see print all, it is backtracking.

Grow the tree

We will use a recursive function growTreeto grow the tree: It’s argument is an array of number that will be used to build the solution, and the partial solutions the the caller has built.

Finding all solution is like growing a tree. For each permutation, it is built from an empty array, the root level.

Then at each level, we will grow the node by appending a number from input to the partial solution each node contains. After appending the number, we recursively call growTree with the new partial solution and a new input that ticks out the number that was just used for partial solution.

We do this for every node in every level.

When we reach leaf node, we must have had a full solution. we append it to a solution array.

class Solution:

    def __init__(self):
        self.sol = []
    def permute(self, nums):
        """
        :type nums: List[int]
        :rtype: List[List[int]]
        Use DFS
        """
        def recur(path, nums):
            if not nums:
                self.sol.append(path)
                return 

            for i in range(len(nums)):
                recur(path + [nums[i]], nums[:i] +  nums[i + 1:])

        recur([], nums)
        return self.sol

size of solution

The number of permutations is n!. Since we have n choice for the first letter, then n – 1 choice for the second slot and so on. Since What we picked for the first slot is independent of other slots, we multiples all the number of choices.

Why is this technique called backtracking

On Wikipedia, backtracking is defined as “a general algorithm that finds all(or some) solutions to some computational problem, notably Constraint satisfaction problem(CSP), that develops the solution incrementally. The potential solutions will be discarded (AKA, backtrack) as soon as the the algorithm deems it to be invalid.

Can we not passed the array?

Since the numbers are unique, and at the beginning, the input numbers are [0,1… len(nums) – 1]. We could use the length of nums passed into each recursive function as the input.

class Solution:
    def __init__(self):
        self.sol = []
        self.nums = []

    def permute(self, nums: 'List[int]') -> 'List[List[int]]':
        def backtrack(swap_pos = 0):
            if swap_pos == len(self.nums):
                self.sol.append(self.nums[:])
                return


            for i in range(swap_pos, len(self.nums)):
                self.nums[swap_pos], self.nums[i] = self.nums[i], self.nums[swap_pos]
                backtrack(swap_pos + 1)
                self.nums[swap_pos], self.nums[i] = self.nums[i], self.nums[swap_pos]

        self.nums = nums
        backtrack()
        return self.sol

In the code above, we are able to use the input to store each candidate solution. As soon as we find a solution, we backtrack so the input is back to the previous state and other branch can use it to build their candidate solution.

Bugs

When I append to solution, I didn’t use copy [:]. So only the address of self.nums is appended and in the end, the solutions are all the same.

Leave a Reply

Your email address will not be published. Required fields are marked *

To create code blocks or other preformatted text, indent by four spaces:

    This will be displayed in a monospaced font. The first four 
    spaces will be stripped off, but all other whitespace
    will be preserved.
    
    Markdown is turned off in code blocks:
     [This is not a link](http://example.com)

To create not a block, but an inline code span, use backticks:

Here is some inline `code`.

For more help see http://daringfireball.net/projects/markdown/syntax