简体   繁体   中英

recursion: find all ways to add elements in an list to get to n

For example,

given a list [1,2,3,4] and `n=4`

my output should be

7:
1+1+1+1=4
1+1+2=4
1+2+1=4
1+3=4
2+2=4
2+1+1=4
3+1=4

I am struggling with the recursion aspect and was hoping for some help with the thought process as well as the code.

I understand that I need to find a base case and I cant find a base case for this problem. I considered that if lst=[] and n==0 then return 0`. Not sure if that works as a base case but if so then how do I continue?

This is how I would do it It's not the most efficient way, but works::

def recursion_list1(numbers, target_num, lst):
    recursion_list2(numbers * target_num, target_num, lst)

def recursion_list2(numbers, target_num, all_lst, partial=[]):
    s = sum(partial)

    # check if the partial sum is equals to target
    if s == target_num:
        if len(partial) >= 2 and partial not in all_lst:
            part = " + ".join([str(a) for a in partial])
            all_lst.append(partial)
            print(f"{part} = {target_num}")
    elif s >= target_num:
        return # if we reach the number why bother to continue

    for i in range(len(numbers)):
        n = numbers[i]
        remaining = numbers[i + 1:]
        recursion_list2(remaining, target_num, all_lst, partial + [n])


if __name__ == "__main__":
    lst = []
    recursion_list1([1,2,3,4], 4, lst)

Let me explain:

Firstly, we create a small function which does ONE thing. It times the list to make it bigger, if that makes sense. Basically, without it, we have a list of [1, 2, 3, 4] . Therefore, the only combinations of numbers that add up to 4 are 1, 3 and 4 . However, when we times the list by the target number, we get a list of [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4] . Therefore, we have access to more combinations such as 1, 1, 1, 1 . You could get rid of the first function and, instead, change the last line in the script to recursion_list1([1,2,3,4] * 4, 4, lst) . Notice the * 4 I added..

Next, we create the second, main function. First, get the sum of a new list, partial. Then, we see if the sum is equal to the target number. If it is, then we run a few more if statements. The first part checks to see in the sum of the list has more than 1 digit. This is because, if we didn't, we would get 4 = 4 as one of the results, which has no addition in it. The next part of the if statement checks to see if the combination is already in a list called all_list. This is crucial as it will help us filter out any duplicates.

Now, if all of these if statements return as true, we print the combination and add it to the list, all_list. Therefore, if the next iteration returns a result identical to the first, then it won't print it as the result is already in our main list.

If the sum of the list is greater then the number, then it stops it as there is no point in continuing.

Finally, we create a for loop so that we can loop through all the values in our list. This is how the for loop works:

Say we get a list of [1, 2, 3, 4] After the first function, it will be [1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4] . The first for loop loops through all the values: 1 then 2 then 3 then 4. However, it also runs the function again, meaning that the for loop is also ran again, this time looping through the second value. Therefore, we get 1, 1 then 1, 2 then 1, 3 then 1, 4, then 1, 1, then 1, 2... and eventually, 2, 1 and 2, 2... and so on, if that makes sense to you.

I hope this helps you understand this recursive function!

My advice would be to separate the recursive nature of the results from the formatting of the results. Ie I wouldn't recurse and construct strings at the same time:

def equations(numbers, target):

    def equations_recursive(numbers, target):
        solutions = []

        for number in numbers:
            if number < target:
                sub_solutions = equations_recursive(numbers, target - number)

                for sub_solution in sub_solutions:
                    if number + sum(sub_solution) == target:
                        solutions.append([number, *sub_solution])
            elif number == target:
                solutions.append([number])

        return solutions

    solutions = equations_recursive(numbers, target)

    return ["{}={}".format('+'.join(map(str, s)), target) for s in solutions if len(s) > 1]

print(*equations([1, 2, 3, 4], 4), sep='\n')

The result of the call to the inner equations_recursive() function is:

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

And the final line of the outer equations() function filters and formats the results:

> python3 test.py
1+1+1+1=4
1+1+2=4
1+2+1=4
1+3=4
2+1+1=4
2+2=4
3+1=4
>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM