-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathcan_sum.py
123 lines (106 loc) · 3.42 KB
/
can_sum.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
"""
Problem Statement:
Write a function canSum(targetSum, numbers) that takes in a target sum and an array
of numbers as arguments.
The function should return a boolean indicating whether or not it is possible to
generate the targetSum using numbers from the array.
You may use an element of the array as many times as needed.
You may assume that all input numbers are positive.
Hints for time complexity:
Considering targetSum = M and number of elements = N
the worst case will be when one of the number in array is 1
so the height of the tree will be M
for every node there will be N branches.
"""
from functools import lru_cache, partial
from utils.decorators import time_this
class CanSum:
def __init__(self, target_sum, numbers):
self.solutions = {
# "recursive": partial(self.recursive, target_sum, numbers),
"dynamic_programming": partial(self.dp, target_sum, numbers),
"dp_lru_cache": partial(self.dp_lru_cache, target_sum, tuple(numbers)),
"dp_tabulation": partial(self.dp_tabulation, target_sum, numbers),
}
@staticmethod
def recursive(target_sum, array):
"""
Time complexity: O(N^M)
Space Complexity: O(M)
"""
for element in array:
new_sum = target_sum - element
if new_sum < 0:
continue
elif new_sum == 0:
return 1
if CanSum.recursive(new_sum, array):
return 1
return 0
@staticmethod
def dp(target_sum, array, memo=None):
"""
Time complexity: O(N*M)
Space Complexity: O(M)
"""
if memo is None:
memo = {}
val = memo.get(target_sum)
if val is not None:
return val
for element in array:
new_sum = target_sum - element
if new_sum < 0:
continue
elif new_sum == 0:
memo[target_sum] = 1
return 1
if CanSum.dp(new_sum, array, memo):
memo[target_sum] = 1
return 1
memo[target_sum] = 0
return 0
@staticmethod
@lru_cache
def dp_lru_cache(target_sum, array):
"""
Time complexity: O(N)
Space Complexity: O(N)
"""
for element in array:
new_sum = target_sum - element
if new_sum < 0:
continue
elif new_sum == 0:
return 1
if CanSum.dp_lru_cache(new_sum, array):
return 1
return 0
@staticmethod
def dp_tabulation(target_sum, array):
"""
Time complexity: O(N*M)
Space Complexity: O(M)
"""
table = [0] * (target_sum + 1)
table[0] = 1
for i in range(target_sum + 1):
if table[i]:
for element in array:
if i + element <= target_sum:
table[i + element] = 1
# print(table)
return table[target_sum]
@staticmethod
@time_this()
def run(func):
print(f"Solution: {func()}")
def execute_all(self):
print("\nSolutions to CanSum\n")
for name, solution in self.solutions.items():
print(f'Algo-Name: {name} {" -" * 90}')
self.run(solution)
print('-' * 100)
CanSum(7, [2, 4, 1]).execute_all()
CanSum(101, [5, 2, 4, 8]).execute_all()
CanSum(300, [7, 14]).execute_all()