I am learning Dynamic Programming from freecodecamp, the instructor is using JavaScript and i know python so i am converting the logic in python.
Long story short, this problem's JavaScript implementation is working fine, but my python implementation is giving strange output.
I have matched the syntax many times and verified the logic, i can't point out where i am going wrong. Any help would be appreciated.
Problem Statement: Create a program to find the smallest sub-array of integers whose sum is equal to targetsum
.
JavaScript Implementation:
const bestsum = (targetsum, numbers, memo={}) => {
if (targetsum in memo) return memo[targetsum];
if (targetsum === 0) return [];
if (targetsum <0) return null;
let shortestcomb = null;
for (let num of numbers){
const remainder = targetsum - num;
const remaindercomb = bestsum(remainder, numbers, memo);
if (remaindercomb !== null){
const combination = [...remaindercomb, num];
if (shortestcomb===null || combination.length < shortestcomb.length){
shortestcomb = combination;
}
}
}
memo[targetsum] = shortestcomb;
return shortestcomb;
}
console.log(bestsum(7, [2, 4, 3]));
console.log(bestsum(100, [1, 2, 5, 25]));
Output:
[ 3, 4 ]
[ 10, 10 ]
My Python Implementation:
def bestsum(targetsum, arr, memo=None):
if memo is None:
memo={}
if targetsum in memo: return memo[targetsum]
if targetsum==0: return []
elif targetsum < 0: return None
shortest = None
for i in arr:
remainder = targetsum-i
seq = bestsum(remainder, arr, memo)
if seq!=None:
seq.append(i)
if (shortest==None or len(seq)<len(shortest)):
shortest = seq
memo[targetsum] = shortest
return shortest
print(bestsum(7, [2, 4, 3]))
print(bestsum(20, [5, 10]))
Output:
[4, 3]
[10, 5, 5, 10]
The obvious answer for the second case is [10, 10]
as that would sum to 20 with the least number of elements, also for the first case the JavaScript output is [3, 4]
whereas python output is [4, 3]
, isn't it strange?
EDIT: Someone marked this question as duplicate, i followed that guide and used a placeholder in place of the mutable default argument, but the output is still the same, what is wrong now?
While an interactive debugger is the most general (and, often, most powerful) way of examining bugs, here a simple bit of scaffolding can reveal much. By adding a print(f"target = {targetsum}; memo = {memo}")
statement just before the end of bestsum
, we get:
target = 5; memo = {5: [5]} target = 10; memo = {5: [5, 5], 10: [10]} target = 15; memo = {5: [5, 5, 10], 10: [10, 5], 15: [10, 5]} target = 20; memo = {5: [5, 5, 10], 10: [10, 5, 5, 10], 15: [10, 5, 5, 10], 20: [10, 5, 5, 10]}
Note how the entries for each target sum keep changing. This shouldn't happen, based on the algorithm. Looking at bestsum
, the entries of memo
come from seq
. Looking for lines that alter seq
, we find seq.append(i)
. This mutates the list, which is why the entries of memo
keep changing, and why the final result is incorrect. The JavaScript version of bestsum
creates a new list for each iteration of the loop body, which is why it doesn't suffer this bug.
Note you could translate the JavaScript directly and use the spread operator, or you could list concatenation: seq = seq + [i]
.
One approach that would have prevented this bug from arising would be to use an immutable type instead of a list. In Python, that would be tuple
. The one wrinkle is than if using tuple concatenation, a single-element tuple must have a comma trailing the element: seq = seq + (i,)
.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments