Why does this solution work in Javascript but not in Python? (Dynamic programming)

Martín Schere

I'm following this tutorial about dynamic programming and I'm struggling to implement memoization in the following problem:

*Write a function called canSum(targetSum, numbers) that returns True only if the numbers in the array can sum to the target sum. All the numbers in the array are positive integers and you can use them more than once for the solution.

Example:

canSum(7, [2, 4]) -> False because you can't form 7 by adding 2 and 4. *

My brute force solution was the following one:

def canSum(targetSum, numbers):
    if targetSum == 0:
        return True
    if targetSum < 0:
        return False

    for n in numbers:
        remainder = targetSum - n
        if canSum(remainder, numbers):
            return True

    return False


print(canSum(7, [2, 3])) # True
print(canSum(7, [5, 3, 4, 7])) # True
print(canSum(7, [2, 4])) # False
print(canSum(8, [2, 3, 5])) # True

Works well, but it'd be faster if we memoized the solutions of the remainders (this is explained at minute 1:28:03 in the video). I did the following with Python, which is exactly what the instructor is doing, but it only returns True and I can't figure out why...

def canSum(targetSum, numbers, memo={}):
    if targetSum in memo:
        return memo[targetSum]
    if targetSum == 0:
        return True
    if targetSum < 0:
        return False

    for n in numbers:
        remainder = targetSum - n
        if canSum(remainder, numbers, memo):
            memo[targetSum] = True
            return True

    memo[targetSum] = False
    return False


print(canSum(7, [2, 3]))
print(canSum(7, [5, 3, 4, 7]))
print(canSum(7, [2, 4]))
print(canSum(8, [2, 3, 5])) # All of them return True
ObjectBerry

You saving mechanism have bug.

When you call function first time:

print(canSum(7, [2, 3]))

This call will return true and it will create key in dictionary with value true( 7 : true).
This is the reason why it doesnt work

Now we will check 3rd call:

print(canSum(7, [2, 4]))

First thing your function is doing is checking if number 7 is in dictionary:

if targetSum in memo:
    return memo[targetSum]

And because from 1st call you alredy have number 7 in dictionary , it will search it and return its value - and from 1st call , value for number 7 is True

This is dictionary before and after first call.

{}                                    # before first call
{1: False, 3: True, 5: True, 7: True} # after first call

After first call , this dictionary will return True for every time you call function with number 7.
And because Python share default argument (it is explained in comment by Jared Smith), every call will return True for number 7

How to fix this ? You must save both targetSum and nums into dictionary and test for both values.

There are two ways to do this:

1st way: Encapsulate targetSum and nums into tuple and use that tuple as key.
This is how will that dict will look

{
  (7, (2, 3)) : True,
  (7, (5, 3, 4, 7)) : True,
  (7, (2, 4)) : False
}

This is implementation of this:

keyTuple = (targetSum, tuple(numbers))
if keyTuple in memo:
    return memo[keyTuple]

if targetSum == 0:
    return True
if targetSum < 0:
    return False

for n in numbers:
    remainder = targetSum - n
    if canSum(remainder, numbers, memo):
        memo[keyTuple] = True
        return True

memo[keyTuple] = False
return False

You must also convert list into tuple , because python doesnt allow lists as keys for dictionaries.

Second way is use dictionary of dictionaries. Something like this.

{
 7: {
   (2,3): True,
   (5, 3, 4, 7): True
   (2,4): False
 }

}

This is implementation :

def canSum(targetSum, numbers, memo={}):
numbersTuple = tuple(numbers)

if targetSum in memo:
    targetDict = memo[targetSum]
    if numbersTuple in targetDict:
        return targetDict[numbersTuple]
else:
    memo[targetSum] = {}

if targetSum == 0:
    return True
if targetSum < 0:
    return False

for n in numbers:
    remainder = targetSum - n
    if canSum(remainder, numbers, memo):
        targetDict = memo[targetSum]
        targetDict[numbersTuple] = True
        return True

targetDict = memo[targetSum]
targetDict[numbersTuple] = False
return False

If you dont understand something , write comment for me :)

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

JavaScript Map: Why does this not work?

Why does `if Exception` work in Python

Project Euler 31: Why does this solution work?

Why does my solution work and this other solution doesnt?

Explanation of Dynamic Programming solution

Why does a dynamic programming solution for word ladders not work?

javascript - Why does this if statement not work?

Why this Javascript promise does not work?

why javascript in webview does not work?

Why javascript (jquery) if statements does not work like php if statements? And what is solution?

Why does my dynamic to_char not work?

Why does my dynamic IEqualityComparer not work?

Dynamic Programming : Why the 1?

JavaScript Functions - Why does this work?

Why does this not work? (Python)

Why >= evaluation does not work Python

python iterator: why does this work?

Why does this python code work?

Why does my mod-mail not work, but deleting messages work in discord.py Python Programming?

Why does this dynamic programming optimization actually make code slower?

Why does my recursive solution to pruning binary tree not work?

Why does howSum solution work in Javascript but not in Python? (Dynamic programming)

Why does the `R` pipe operator `|>` not work in the reactive programming using Shiny?

Why does this not work? Python webscraping

Why does dynamic work in the first case but not in the second?

Why does the addEventListener property does not work on a dynamic HTMLcollection object?

Dynamic programming code works in javascript but not in python

Why dynamic Linq does not work with .contains?

Why does SUMIFS not work for this solution?