Skip to content

Commit ea9af2e

Browse files
committed
LC 879. Profitable Schemes (Python Mem)
1 parent 68c7afd commit ea9af2e

File tree

3 files changed

+117
-0
lines changed

3 files changed

+117
-0
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ Solutions to LeetCode problems. The first column links to the problem in LeetCod
324324
| [872. Leaf-Similar Trees][lc872] | 🟢 Easy | [![python](res/py.png)][lc872py] |
325325
| [875. Koko Eating Bananas][lc875] | 🟠 Medium | [![python](res/py.png)][lc875py] [![rust](res/rs.png)][lc875rs] |
326326
| [876. Middle of the Linked List][lc876] | 🟢 Easy | [![python](res/py.png)][lc876py] |
327+
| [879. Profitable Schemes][lc879] | 🔴 Hard | [![python](res/py.png)][lc879py] |
327328
| [881. Boats to Save People][lc881] | 🟠 Medium | [![python](res/py.png)][lc881py] [![rust](res/rs.png)][lc881rs] |
328329
| [886. Possible Bipartition][lc886] | 🟠 Medium | [![python](res/py.png)][lc886py] |
329330
| [890. Find and Replace Pattern][lc890] | 🟠 Medium | [![python](res/py.png)][lc890py] |
@@ -1149,6 +1150,8 @@ Solutions to LeetCode problems. The first column links to the problem in LeetCod
11491150
[lc875rs]: leetcode/koko-eating-bananas.rs
11501151
[lc876]: https://leetcode.com/problems/middle-of-the-linked-list/
11511152
[lc876py]: leetcode/middle-of-the-linked-list.py
1153+
[lc879]: https://leetcode.com/problems/profitable-schemes/
1154+
[lc879py]: leetcode/profitable-schemes.py
11521155
[lc881]: https://leetcode.com/problems/boats-to-save-people/
11531156
[lc881py]: leetcode/boats-to-save-people.py
11541157
[lc881rs]: leetcode/boats-to-save-people.rs

leetcode/profitable-schemes.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[
2+
[5, 3, [2, 2], [2, 3], 2],
3+
[10, 5, [2, 3, 5], [6, 7, 8], 7],
4+
[1, 1, [1, 1, 1, 1, 2, 2, 1, 2, 1, 1], [0, 1, 0, 0, 1, 1, 1, 0, 2, 2], 4],
5+
[
6+
100,
7+
100,
8+
[
9+
18, 58, 88, 52, 54, 13, 50, 66, 83, 61, 100, 54, 60, 80, 1, 19, 78, 54,
10+
67, 20, 57, 46, 12, 6, 14, 43, 64, 81, 30, 60, 48, 53, 86, 71, 51, 23, 71,
11+
87, 95, 69, 11, 12, 41, 36, 69, 89, 91, 10, 98, 31, 67, 85, 16, 83, 83,
12+
14, 14, 71, 33, 5, 40, 61, 22, 19, 34, 70, 50, 21, 91, 77, 4, 36, 16, 38,
13+
56, 23, 68, 51, 71, 38, 63, 52, 14, 47, 25, 57, 95, 35, 58, 32, 1, 39, 48,
14+
33, 89, 9, 1, 95, 90, 78
15+
],
16+
[
17+
96, 77, 37, 98, 66, 44, 18, 37, 47, 9, 38, 82, 74, 12, 71, 31, 80, 64, 15,
18+
45, 85, 52, 70, 53, 94, 90, 90, 14, 98, 22, 33, 39, 18, 22, 10, 46, 6, 19,
19+
25, 50, 33, 15, 63, 93, 35, 0, 76, 44, 37, 68, 35, 80, 70, 66, 4, 88, 66,
20+
93, 49, 19, 25, 90, 21, 59, 17, 40, 46, 79, 5, 41, 2, 37, 27, 92, 0, 53,
21+
57, 91, 75, 0, 42, 100, 16, 97, 83, 75, 57, 61, 73, 21, 63, 97, 75, 95,
22+
84, 14, 98, 47, 0, 13
23+
],
24+
5570822
25+
]
26+
]

leetcode/profitable-schemes.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# 879. Profitable Schemes
2+
# 🔴 Hard
3+
#
4+
# https://leetcode.com/problems/profitable-schemes/
5+
#
6+
# Tags: Array - Dynamic Programming
7+
8+
import json
9+
import os
10+
import timeit
11+
from functools import cache
12+
from typing import List
13+
14+
15+
# Iterate over the indexes of the jobs, gang members and profit,
16+
# computing the result of doing and skipping this job, if we go over
17+
# the maximum allowed gang members, we return 0, this combination is
18+
# not valid, if we reach the end of the array, we return 1 if we
19+
# achieved the minimum profit and 0 if we didn't.
20+
#
21+
# Time complexity: O(n*mp*g) - Where n is the max number of gang members
22+
# we can choose, mp is the minimum profit we need to make and g is the
23+
# length of the profit and group arrays, these three are the ranges of
24+
# the three parameters to the function that we are using to compute the
25+
# results, since we are memoizing the function, that is the maximum
26+
# number of times we may call it.
27+
# Space complexity: O(n*mp*g) - The size of the cache, the call stack
28+
# can grow to size g.
29+
#
30+
# Runtime 3903 ms Beats 26.67%
31+
# Memory 682.3 MB Beats 5.71%
32+
class Memoization:
33+
def profitableSchemes(
34+
self, n: int, minProfit: int, group: List[int], profit: List[int]
35+
) -> int:
36+
# Explore the possibilities
37+
# idx: the index we are checking.
38+
# p: the profit up to that point.
39+
# g: the number of people pooled up to that point.
40+
# return: the number of profitable schemes of that branch.
41+
@cache
42+
def dfs(i: int, p: int, g: int) -> int:
43+
# Base case, we went over the group size limit.
44+
if g > n:
45+
return 0
46+
# Base case, we run out of indexes.
47+
if i == len(group):
48+
return int(p == minProfit)
49+
return dfs(
50+
i + 1, min(minProfit, p + profit[i]), g + group[i]
51+
) + dfs(i + 1, p, g)
52+
53+
# Return the result of the initial call.
54+
return dfs(0, 0, 0) % (10**9 + 7)
55+
56+
57+
# TODO: add the dynamic programming solution.
58+
59+
60+
def test():
61+
executors = [
62+
Memoization,
63+
]
64+
__location__ = os.path.realpath(
65+
os.path.join(os.getcwd(), os.path.dirname(__file__))
66+
)
67+
filename = os.path.splitext(os.path.basename(__file__))[0] + ".json"
68+
with open(os.path.join(__location__, filename)) as json_file:
69+
tests = json.load(json_file)
70+
for executor in executors:
71+
start = timeit.default_timer()
72+
for _ in range(1):
73+
for col, t in enumerate(tests):
74+
sol = executor()
75+
result = sol.profitableSchemes(t[0], t[1], t[2], t[3])
76+
exp = t[4]
77+
assert result == exp, (
78+
f"\033[93m» {result} <> {exp}\033[91m for"
79+
+ f" test {col} using \033[1m{executor.__name__}"
80+
)
81+
stop = timeit.default_timer()
82+
used = str(round(stop - start, 5))
83+
cols = "{0:20}{1:10}{2:10}"
84+
res = cols.format(executor.__name__, used, "seconds")
85+
print(f"\033[92m» {res}\033[0m")
86+
87+
88+
test()

0 commit comments

Comments
 (0)