Problem Statement:-
There is a group of n
members, and a list of various crimes they could commit. The i<sup>th</sup>
crime generates a profit[i]
and requires group[i]
members to participate in it. If a member participates in one crime, that member can't participate in another crime.
Let's call a profitable scheme any subset of these crimes that generates at least minProfit
profit, and the total number of members participating in that subset of crimes is at most n
.
Return the number of schemes that can be chosen. Since the answer may be very large, return it modulo 10<sup>9</sup> + 7
.
Link: https://leetcode.com/problems/profitable-schemes/description/
Problem Explanation with examples:-
Example 1
Input: n = 5, minProfit = 3, group = [2,2], profit = [2,3]
Output: 2
Explanation: To make a profit of at least 3, the group could either commit crimes 0 and 1, or just crime 1.
In total, there are 2 schemes.
Example 2
Input: n = 10, minProfit = 5, group = [2,3,5], profit = [6,7,8]
Output: 7
Explanation: To make a profit of at least 5, the group could commit any crimes, as long as they commit one.
There are 7 possible schemes: (0), (1), (2), (0,1), (0,2), (1,2), and (0,1,2).
Constraints
1 <= n <= 100
0 <= minProfit <= 100
1 <= group.length <= 100
1 <= group[i] <= 100
profit.length == group.length
0 <= profit[i] <= 100
Intuition:-
There are 3 changing parameters: i(the index in array), n(the number of members), p(the profit).
The dp array is 3D, dp[i][n][p] means the number of schemes with i members and p profit.
There is a skip case where we simply copy the previous value, dp[i][n][p] = dp[i - 1][n][p].
There is a take case where we add the previous value, dp[i][n][p] = dp[i - 1][n - members][max(0, p - earn)].
The final answer is the sum of dp[length][j][minProfit] for j in range(n + 1).
Solution:-
Initialize the dp array of size (length + 1) (n + 1) (minProfit + 1) with 0.
Set dp[0][0][0] = 1.
Loop through the dp array, i from 1 to length + 1, j from 0 to n + 1, k from 0 to minProfit + 1.
If j < members, dp[i][j][k] = dp[i - 1][j][k].
Else, dp[i][j][k] = (dp[i - 1][j][k] + dp[i - 1][j - members][max(0, k - earn)]) % MOD.
Return the sum of dp[length][j][minProfit] for j in range(n + 1).
Code:-
JAVA Solution
class Solution {
public int profitableSchemes(int n, int minProfit, int[] group, int[] profit) {
int MOD = 1000000007;
int length = group.length;
int[][][] dp = new int[length + 1][n + 1][minProfit + 1];
dp[0][0][0] = 1;
for (int i = 1; i <= length; i++) {
int members = group[i - 1];
int earn = profit[i - 1];
for (int j = 0; j <= n; j++) {
for (int k = 0; k <= minProfit; k++) {
if (j < members) {
dp[i][j][k] = dp[i - 1][j][k];
} else {
dp[i][j][k] = (dp[i - 1][j][k] + dp[i - 1][j - members][Math.max(0, k - earn)]) % MOD;
}
}
}
}
int total = 0;
for (int j = 0; j <= n; j++) {
total = (total + dp[length][j][minProfit]) % MOD;
}
return total;
}
}
Python Solution
class Solution:
def profitableSchemes(self, n: int, minProfit: int, group: List[int], profit: List[int]) -> int:
MOD = 10**9 + 7
length = len(group)
dp = [[[0] * (minProfit + 1) for _ in range(n + 1)] for _ in range(length + 1)]
dp[0][0][0] = 1
for i in range(1, length + 1):
members, earn = group[i - 1], profit[i - 1]
for j in range(n + 1):
for k in range(minProfit + 1):
if j < members:
dp[i][j][k] = dp[i - 1][j][k]
else:
dp[i][j][k] = (dp[i - 1][j][k] + dp[i - 1][j - members][max(0, k - earn)]) % MOD
total = sum(dp[length][j][minProfit] for j in range(n + 1))
return total % MOD
Complexity Analysis:-
TIME:-
The time complexity of the given Python code is O(n * *length \ minProfit)** where n is the number of members, length is the length of group and profit, minProfit is the minimum profit as we need to loop through all possible profits.
SPACE:-
The space complexity of the code is also O(n * *length \ minProfit)** where n is the number of members, length is the length of group and profit, minProfit is the minimum profit as we are using a 3D dp array.