Search code examples
pythonalgorithmbacktracking

variable value in a backtracking solution is not going back to its original state


I was trying to build a solution to the problem of generating all possible combination of k of the length n

ex: k = 4, n = 2

output :

[1, 1]
[1, 2]
[1, 3]
[1, 4]
[2, 1]
[2, 2]
[2, 3]
[2, 4]
[3, 1]
[3, 2]
[3, 3]
[3, 4]
[4, 1]
[4, 2]
[4, 3]
[4, 4]

Here is the pseudocode for the logic that I implemented

def backTrack(arr):
    if length(arr) == k:
        return

    loop through from 1 to n <- for i in range(1, n+1):
        i = value of loop
        add i to an array variable arr <- arr.append(i)
        backtrack(arr) <- recurse
        remove last index value from arr <- arr = arr[:-1]

for this above code, I am supposed to get the following values

on depth 1:
   the loop starts with 1
   and arr = [1]
   
   then it recuses to depth 2
      the loop starts with 1
       and arr = [1, 1]
       since the length of arr = k =2 it wont recurse further and continue
       arr = arr[:-1] = arr = [1]

       then i will be 2 
       and arr = [1,2]
       similarly [1, 3] and [1, 4] and then it goes to depth 1 or the parent call

on depth 1
  value of i = 1
   and arr  = 1
   now, arr = arr[:-1] that makes arr = []
  and now i becomes 2 and the process continues
       

But debugging the code written with the following pseudo code, shows that on depth 1 the arr never get back to being [1] but become [1, 1] I am still struggling to understand why it is so.

Below is the debugging solution with the print statements

class Solution(object):
    def combine(self, n, k):
    
        def backTrack(arr, result, depth):
            if len(arr) == k:
                return
    
            for i in range(1, n + 1):
                arr.append(i)
                print("depth = " + str(depth) + ", i = " + str(i) + ", arr=" + str(arr))
                backTrack(arr, result, depth + 1)
            
                print("depth -> " + str(depth) + ", i-> " + str(i) + ", arr-> " + str(arr))
                arr = arr[:-1]

        
        return backTrack([], [], 1)



ob = Solution()
result = ob.combine(4, 2)

Below is the debugged output

depth = 1, i = 1, arr=[1]
depth = 2, i = 1, arr=[1, 1]
depth -> 2, i-> 1, arr-> [1, 1]
depth = 2, i = 2, arr=[1, 2]
depth -> 2, i-> 2, arr-> [1, 2]
depth = 2, i = 3, arr=[1, 3]
depth -> 2, i-> 3, arr-> [1, 3]
depth = 2, i = 4, arr=[1, 4]
depth -> 2, i-> 4, arr-> [1, 4]
depth -> 1, i-> 1, arr-> [1, 1] * going back to parent call arr never becomes 1
depth = 1, i = 2, arr=[1, 2]
depth -> 1, i-> 2, arr-> [1, 2]
depth = 1, i = 3, arr=[1, 3]
depth -> 1, i-> 3, arr-> [1, 3]
depth = 1, i = 4, arr=[1, 4]
depth -> 1, i-> 4, arr-> [1, 4]

I have marked the debugger output in * to show the state of the arr in the parent call never gets back to being 1

I want to understand why it is so.


Solution

  • arr = arr[:-1] creates a new copy of arr with the last element removed and assigns it to the local variable arr. This means that the arrs in other scopes of the recursive calls reference some other list which still has the last element.

    You need to remove the last element from this list by writing arr.pop().

    If you need further explanation about mutable and immutables in python and why it works this way please comment.