![]() |
VOOZH | about |
Given an array arr[] of n elements. The task is to find the number of non-empty subsets whose product of elements is less than or equal to a given integer k.
Examples:
Input: arr[] = [2, 4, 5, 3], k = 12
Output: 8
Explanation: All possible subsets whose products are less than 12 are: (2), (4), (5), (3), (2, 4), (2, 5), (2, 3), (4, 3)Input: arr[] = [9, 8, 3], k = 2
Output: 0
Explanation: There are no subsets with products less than or equal to 2.
Table of Content
We can identify a recursive pattern in this problem. There are two state variables:
We consider two cases for recursion:
Exclude the current element: The current element is not included in the subset, and the product remains unchanged. This corresponds to:
- numOfSubsets(i + 1, currentProduct, k).
Include the current element: The current element is included in the subset, and the product is updated as currentProduct * arr[i]. This corresponds to:
- numOfSubsets(i + 1, currentProduct * arr[i], k)
Recurrence relation:
- numOfSubsets(i, currentProduct, k) = numOfSubsets(i+1, currentProduct, k) + numOfSubsets(i+1, currentProduct*arr[i], k)
Base Case: If i == n (all elements have been processed), return 1 if the currentProduct less than equal to k else 0.
11
If we notice carefully, we can observe that the above recursive solution holds the following two properties of Dynamic Programming:
1.Optimal Substructure: Maximum subsequence length for a given i, j and currentProduct , i.e. numOfSubsets(i + 1, currentProduct, k), depends on the optimal solutions of the subproblems numOfSubsets(i + 1, currentProduct , k) and numOfSubsets(i + 1, currentProduct * arr[i], k). By choosing the total of these optimal substructures, we can efficiently calculate answer.
2. Overlapping Subproblems: While applying a recursive approach in this problem, we notice that certain subproblems are computed multiple times. For example while considering arr = [2, 3, 6, 8] and k = 10, countSubsets(3, 6, 10, arr) computed multiple times from countSubsets(2, 1, 10, arr) and countSubsets(2, 6, 10, arr).
11
We create a 2D array dp[n+1][k+1], such that dp[i][j] equals to the number of subsets having product value less than equal to j from subsets of arr[0...i-1].
We fill the dp array as following:
- We initialize all values of dp[i][j] as 1 because we take empty subsequence as our base case.
Iterate over all the values of arr[i] from left to right and for each arr[i], iterate over all the possible values of k i.e. from 1 to k (both inclusive) and fill the dp array as following:
dp[i][j] = dp[i-1][j]
if j>=arr[i-1]
dp[i][j] +=dp[i-1][j/arr[i-1]]
This can be explained as there are only two cases either we take element arr[i] or we don't. We take a element only when it's value is less than or equal to j. Then we look for subsets ending at i-1 such that their product with arr[i] should be atmost k. Product of those subsets will be less than or equal to a j/arr[i-1] so we get this value from dp[i-1][j/arr[i-1]] The number of subsets from set arr[0..n] having product value as less than or equal to k will be dp[n][k].
11
In previous approach the current value dp[i][j] is only depend upon the current and previous row values of DP. So to optimize the space complexity we use a two 1D array of size k+1 namely prevState and curState to store the computations. The final answer is equal to curState[k]-1;
11
Related article: