-1

I have made two implementations of a backtracking algorithm to solve this challenge on Codewars ( https://www.codewars.com/kata/5a6b24d4e626c59d5b000066 ) . My problem is that I grasp why the first implementation works but not why the second one . I think that my problem is in the return statement in the last line with the hash signs . I don't get why when the backtracking is terminating , since a solution was found, the second implementation returns the right solution instead of an empty list . Is it because when the solution is passed to the previous call of the function his value in the previous call ( which was with an element less ) is overwritten with the complete solution ?

First :

def square_sums_row(n):
    a , sol = [ x for x in range(1,n+1)] , []
    def recurse(a,sol):
        if a == [] : 
            return sol 
        for i,x in enumerate(a) :
            if is_valid(x,sol) :
                sol.append(x)
                iterate = recurse(a[:i]+a[i+1:],sol) ###########
                if iterate : ###########
                    return iterate #########
                sol.pop(-1)
        return False
    def is_valid(x,sol):
        if len(sol) == 0 :
            return True
        if (( sol[-1] + x )**0.5) % 1 == 0:
            return True
        return False
    return recurse(a,sol)

Second :

def square_sums_row(n):
    s , sol = [ x for x in range(1,n+1)] , []
    def recurse(s,sol):
        if s == [] :  
            return sol
        for i,x in enumerate(s) :
            if is_valid(x,sol) :
                sol.append(x)
                if recurse(s[:i]+s[i+1:],sol) : ###########
                    return sol ##############
                sol.pop(-1)
        return False
    def is_valid(x,sol):
        if len(sol) == 0 :
            return True
        if (( sol[-1] + x )**0.5) % 1 == 0:
            return True
        return False
    return recurse(s,sol)
Tortar
  • 625
  • 5
  • 15

2 Answers2

1

It works because they return the same, both solutions return sol. It's just that the second one returns the variable sol directly, whereas the first one returns the output of the function (which is the same variable sol passed as argument).

Ajordat
  • 1,320
  • 2
  • 7
  • 19
  • Yes , but my problem is that the variable sol was already defined in the previous calls with a shorter list , why is it not going to pass for example with n = 15 which solution is [8, 1, 15, 10, 6, 3, 13, 12, 4, 5, 11, 14, 2, 7, 9] after first call [8, 1, 15, 10, 6, 3, 13, 12, 4, 5, 11, 14, 2, 7,9] then [8, 1, 15, 10, 6, 3, 13, 12, 4, 5, 11, 14, 2,7] ecc... until [ ] ? – Tortar Feb 07 '20 at 10:59
  • In the first case I define a variable which is overwritten at every call with the *right* variable sol . In the second case I didn't do it . – Tortar Feb 07 '20 at 11:02
1

To expand on the other answer, there is only one list object sol that is being passed around and returned. It's never copied. Here's another solution to emphasise that point. Here sol is not an argument anywhere, it's just taken from the closure, and only booleans are returned by the inner functions.

def square_sums_row(n):
    sol = []

    def recurse(s):
        if s == []:
            return True
        for i, x in enumerate(s):
            if is_valid(x):
                sol.append(x)
                iterate = recurse(s[:i] + s[i + 1:])  ###########
                if iterate:  ###########
                    return True
                sol.pop(-1)
        return False

    def is_valid(x):
        if len(sol) == 0:
            return True
        if ((sol[-1] + x) ** 0.5) % 1 == 0:
            return True
        return False

    if recurse([x for x in range(1, n + 1)]):
        return sol
    else:
        return False

Alex Hall
  • 34,833
  • 5
  • 57
  • 89
  • Ahh ok I think that I understood...the object is unique , I thought that a new object was created at every iteration . To do so I have to copy the variable explicitly right? Thank you ! – Tortar Feb 07 '20 at 11:19
  • @Tortar exactly, or create a new list by other means, e.g. with slicing or `+` as you've done with `s`. – Alex Hall Feb 07 '20 at 11:20