SoFunction
Updated on 2024-12-19

python Backtracking Templates Explained

What is the retrospective method

Backtracking (exploration and backtracking) is a kind of selection of the best search method, also known as the trial method, according to the selection of the best conditions to search forward in order to achieve the goal. But when the exploration to a certain step, found that the original choice is not optimal or can not reach the goal, it will be returned to a step to choose again, this can not go back to go back to the technology for the backtracking method, and to meet the conditions of the backtracking of a certain state of the point is called "back to the point".

The problem of arranging all elements without duplicates

Given a list with all its elements distinct, it is required to return the full permutation of the list's elements.

Let n = len(list), then this problem can be considered as an n-forked tree, dfs this tree, the backtracking point in this problem is when the depth (i.e., the length of the templist) is n, and the backtracking condition is that the current element has already appeared in the templist.

Backtracking versus recursion:

Backtracking is an idea, recursion is a form of it

class Solution(object):

  The #rtlist is used to store all the returns of all alignments, and the templist is used to generate each alignment.
  def backtrack(self,rtlist,templist,nums):
    if(len(templist) == len(nums)):
      (templist[:])
    else:
      for i in nums:

        if(i in templist): # If there is already an i in the current arrangement, then continue, which is equivalent to branch bounding, i.e., not searching the subtree of the current node.
          continue
        (i)
        (rtlist,templist,nums)
        () # Replace the ending element with the next value in nums, traversing the next subtree

  def permute(self,nums):
    rtlist = []
    templist = []
    (rtlist,templist,nums)
    return rtlist

Tree structure when nums=[1,2,3]:

The key thing is to identify good branch limits as well as backtracking points.

There is a question of whether it is possible to remove the newly added elements from the nums at each recursion. In fact, the time complexity of this will not be reduced too much because it still takes some time to operate on the list, and the time complexity of the original solution is not too bad because of the branching limit.

Full Arrangement with Repeated Elements

The difference between this problem and the above is mainly the difference in branch bounds, you can't use the occurrence of duplicate elements as a backtracking condition anymore, otherwise all of them are not satisfied.

Here we should use a counter to record the number of times each element appears in the nums, if the current element exceeds the number of times, then return, but here there is another problem is that the same arrangement may occur more than once, the solution here is that the same layer is not allowed to duplicate the elements, there are two solutions, one is to pass directly into the distinct array, and the other is to use a collection of record The current layer has been used in the elements.

The first method:

from collections import Counter

class Solution(object):

  def backtrack(self, rtlist, tmplist, counter, nums, length):
    if len(tmplist) == length:#Backtracking point
      (tmplist[:])
    else:
      for i in nums:# Traverse horizontally
        if counter[i] == 0:#Branch limits
          continue

        counter[i] -= 1
        (i)
        (rtlist, tmplist, counter, nums, length)# Vertical traversal
        counter[i] += 1
        ()

  def permuteUnique(self, nums):

    rtlist, tmplist, counter = [], [], Counter(nums)
    length = len(nums)
    (rtlist, tmplist, counter, list(set(nums)), length)

    return rtlist

second type

from collections import Counter

class Solution(object):

  def backtrack(self, rtlist, tmplist, level, counter, nums):
    if len(tmplist) == len(nums):
      (tmplist[:])
    else:
      for i in nums:
        if i in level or counter[i] == 0:
          continue

        counter[i] -= 1

        (i)
        (i)
        (rtlist, tmplist, set(), counter, nums)

        counter[i] += 1
        ()


  def permuteUnique(self, nums):
    if not nums:
      return []
    rtlist, tmplist, level, counter = [], [], set(), Counter(nums)
    (rtlist, tmplist, level, counter, nums)

    return rtlist

In the recursive can not be used "=" to modify the parent function of the variable, because "=" can only change the variable pointing to, to modify the parent function of the variable to be modified directly in memory, for example, into the container can be directly found in the variable memory address. Usually use ().

For example in the above program if we want to recover the counter at the backtracking point we can't use counter = Counter(nums) but we should modify counter[key] one by one.

summarize

The backtracking method is actually to consider the original problem as a tree, we traverse the tree to return at the impossible, not at traverse the subtree of this node and return when the requirements are met.

So in the backtracking method, the key thing is to find reasonable branch limits (important), and return conditions.

More pleaseconsultation

Traversal methods for multinomial trees:

def travel(root):
 Iterate over root
 for subtree_root in All nodes in the current layer:
travel(subtree_root)

Traversal can be accomplished by performing travel on all nodes of a layer in for, and because travel is performed on all subtrees of all nodes.

This python backtracking method template above is all that I have shared with you, I hope to give you a reference, and I hope you will support me more.