'Python: Recursive Function. How to return all subsets of targetsum
My code is not showing the shortest subset eg [7] or it is not reading all the subsets, [7], [3,4] to return the shortest subset. Can explain why only 1 set of result is return and how should I modify it to show all subset? Thanks
Image of Code that i wanted to follow as below
def howsum(targetsum,numbers,combo=None):
if combo == None:
combo = list()
if targetsum == 0: return [ ]
if targetsum < 0: return None
shortcombo = None
for number in numbers:
remainder = targetsum - number
combo = howsum(remainder,numbers,combo)
if combo != None:
combo.append(number)
if shortcombo == None or len(shortcombo) > len(combo):
shortcombo = combo
return shortcombo
return shortcombo
print(howsum(7,[4,3,7]))
Solution 1:[1]
Wrote code that closely matches the original JavaScript.
Although JavaScript names will work, I refactored function and variable names to agree with Python style, namely:
- Function names should be lowercase, with words separated by underscores as necessary to improve readability.
- Variable names follow the same convention as function names.
Code
def best_sum(target_sum, numbers):
if target_sum == 0: return []
if target_sum < 0: return None
shortest_combination = None
for num in numbers:
remainder = target_sum - num
remainder_combination = best_sum(remainder, numbers)
if remainder_combination != None:
combination = [*remainder_combination, num] # Python * equivalent to JavaSscript ...
if shortest_combination == None or len(combination) < len(shortest_combination):
shortest_combination = combination
return shortest_combination
Test
print(bestSum(7, [3, 4, 7])) # Output: [7]
Using Memoization (i.e. caching)
def best_sum(target_sum, numbers, memo = None):
if memo is None:
memo = {0:[]}
if target_sum < 0:
return None
if target_sum in memo:
return memo[target_sum]
shortest_combination = None
for num in numbers:
remainder = target_sum - num
remainder_combination = best_sum(remainder, numbers, memo)
if remainder_combination != None:
combination = [*remainder_combination, num] # Python * equivalent to JavaSscript ...
if shortest_combination == None or len(combination) < len(shortest_combination):
shortest_combination = combination
memo[target_sum] = shortest_combination
return memo[target_sum]
print(best_sum(7, [3, 4, 7])) # Output: 7
# Following very slow on non-memoized version
print(best_sum(100,[10,1,25])) # Output: [25, 25, 25, 25]
Solution 2:[2]
I am not sure about this but while defining a function in python and giving 2 sets of codes it is not actually performing the second set of the code when calling out the function. I got the same problem with some other project. And I got no answers but saying I did some wrong in the code!!!
Solution 3:[3]
Added memoization, however with 1 inside sets of num. the results gone haywire.
def best_sum(target_sum, numbers,memo=None):
if memo == None:
memo = dict()
if target_sum in memo:
return memo[target_sum]
if target_sum == 0: return []
if target_sum < 0: return None
shortest_combination = None
for num in numbers:
remainder = target_sum - num
remainder_combination = best_sum(remainder, numbers,memo)
if remainder_combination != None:
remainder_combination.append(num)
combination = remainder_combination
if shortest_combination == None or len(combination) < len(shortest_combination):
shortest_combination = combination
memo[target_sum] = shortest_combination
return shortest_combination
print(best_sum(100,[5,1,25]))
This code by answer posted by DarylG works. By changing the .append
to [*list,var]
However I dont understand why is the result different between function append and *
def best_sum(target_sum, numbers,memo=None):
if memo == None:
memo = dict()
if target_sum in memo:
return memo[target_sum]
if target_sum == 0: return []
if target_sum < 0: return None
shortest_combination = None
for num in numbers:
remainder = target_sum - num
remainder_combination = best_sum(remainder, numbers,memo)
if remainder_combination != None:
combination = [*remainder_combination,num] #this line from append to *
if shortest_combination == None or len(combination) < len(shortest_combination):
shortest_combination = combination
memo[target_sum] = shortest_combination
return shortest_combination
print(best_sum(100,[5,1,25]))
Solution 4:[4]
I checked out your code. What I felt missing was
Incorrect placement of return and storing the values inside of combo (set instead of list).
def howsum(targetsum,numbers,combo=None): if combo == None: combo = set() if targetsum == 0: return [ ] if targetsum < 0: return None for idx,number in enumerate(numbers): remainder = targetsum - number if howsum(remainder,numbers[idx:],combo) != None: combo.add(number) else: return combo return None
print(howsum(7,[7,3,4,2,5]))
Hope this helps. While this gives you a solution I would recommend using a different way to solve such issues (twoSum solutions) or two pointer approach with O(n).
Solution 5:[5]
In addition to using memo/any variable for memoization, you can employ functools.lru_cache method. Just remember to typecast the input while testing.
import functools
@functools.lru_cache(maxsize=4)
def howsum(targetnum, num_list):
if targetnum == 0:
return []
if targetnum < 0:
return None
for num in num_list:
rem = targetnum - num
rem_val = howsum(rem, num_list)
if rem_val is not None:
rem_val.append(num)
return rem_val
return None
print(howsum(7, tuple([5, 3, 4, 7])))
print(howsum(8, tuple([3, 4, 2])))
print(howsum(300, tuple([7, 14])))
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Sasidhar Mankala |
Solution 3 | |
Solution 4 | |
Solution 5 | Vishnuraj Rajendran |