Number of subsets with product less than k using DP

Last Updated : 9 Dec, 2024

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.

Using Recursion - O(2^n) Time and O(n) Space

We can identify a recursive pattern in this problem. There are two state variables:

  1. The current index i in the array arr[].
  2. The cumulative product currentProduct of the subsets being considered.

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.

C++
// A C++ program for Number of subsets 
// with product less than k using recursion
#include <bits/stdc++.h>
using namespace std;

// Recursive function to count subsets whose product 
// is less than or equal to k
int countSubsets(int i, int currentProduct, int k, vector<int> &arr) {
  
    // Get the size of the array
    int n = arr.size();

    // Base case: if we have considered all elements
    // Return 1 if the current product is less than or equal to k,
    // otherwise return 0
    if (i == n)
        return (currentProduct <= k);

    // Case 1: Exclude the current element and move to the next
    int exclude = countSubsets(i + 1, currentProduct, k, arr);

    // Case 2: Include the current element in the subset
    int include = 0;
  
    // Only include the current element if the product remains <= k
    if ((arr[i] * currentProduct) <= k)
        include = countSubsets(i + 1, currentProduct * arr[i], k, arr);

    // Return the total count of subsets including both cases
    return (include + exclude);
}


int numOfSubsets(vector<int>& arr, int k) {
  
    // Call the recursive function starting from index 0
  	// Initial product of 1
    // Subtract 1 from the result to exclude the empty subset
    return countSubsets(0, 1, k, arr) - 1;
}

int main() {
  
    vector<int> arr = {1, 2, 3, 4};
    int k = 10;
    cout << numOfSubsets(arr, k);
    return 0;
}
Java
// A Java program for Number of subsets 
// with product less than k using recursion
import java.util.*;

class GfG {

    // Recursive function to count subsets whose product is
    // less than or equal to k
    static int countSubsets(int i, int currentProduct, int k, int[] arr) {
        int n = arr.length;

        // Base case: if we have considered all elements
        if (i == n)
            return (currentProduct <= k) ? 1 : 0;

        // Case 1: Exclude the current element
        int exclude = countSubsets(i + 1, currentProduct, k, arr);

        // Case 2: Include the current element
        int include = 0;
        if ((arr[i] * currentProduct) <= k)
            include = countSubsets(i + 1, currentProduct * arr[i], k, arr);

        return include + exclude;
    }

    static int numOfSubsets(int[] arr, int k) {
      
        // Subtract 1 to exclude the empty subset
        return countSubsets(0, 1, k, arr) - 1; 
    }

    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4};
        int k = 10;
        System.out.println(numOfSubsets(arr, k));
    }
}
Python
# A Python program for Number of subsets 
# with product less than k using recursion

def countSubsets(i, currentProduct, k, arr):
    n = len(arr)

    # Base case: if we have considered all elements
    if i == n:
        return 1 if currentProduct <= k else 0

    # Case 1: Exclude the current element
    exclude = countSubsets(i + 1, currentProduct, k, arr)

    # Case 2: Include the current element
    include = 0
    if currentProduct * arr[i] <= k:
        include = countSubsets(i + 1, currentProduct * arr[i], k, arr)

    return include + exclude

def numOfSubsets(arr, k):
  
    # Subtract 1 to exclude the empty subset
    return countSubsets(0, 1, k, arr) - 1

if __name__ == "__main__":
    arr = [1, 2, 3, 4]
    k = 10
    print(numOfSubsets(arr, k))
C#
// A C# program for Number of subsets 
// with product less than k using recursion
using System;

class GfG {
  
    // Recursive function to count subsets whose 
    // product is less than or equal to k
    static int CountSubsets(int i, int currentProduct, int k, int[] arr){
      
        int n = arr.Length;

        // Base case: if we have considered all elements
        if (i == n)
            return currentProduct <= k ? 1 : 0;

        // Case 1: Exclude the current element
        int exclude = CountSubsets(i + 1, currentProduct, k, arr);

        // Case 2: Include the current element
        int include = 0;
        if (currentProduct * arr[i] <= k)
            include = CountSubsets(i + 1, currentProduct * arr[i], k, arr);

        return include + exclude;
    }

    
    static int numOfSubsets(int[] arr, int k){
      
        // Subtract 1 to exclude the empty subset
        return CountSubsets(0, 1, k, arr) - 1;
    }

    static void Main(string[] args){
      
        int[] arr = { 1, 2, 3, 4 };
        int k = 10;
        Console.WriteLine(numOfSubsets(arr, k));
    }
}
JavaScript
// A Javascript program for Number of subsets 
// with product less than k using recursion

function countSubsets(i, currentProduct, k, arr) {
    let n = arr.length;

    // Base case: if we have considered all elements
    if (i === n) {
        return currentProduct <= k ? 1 : 0;
    }

    // Case 1: Exclude the current element
    let exclude = countSubsets(i + 1, currentProduct, k, arr);

    // Case 2: Include the current element
    let include = 0;
    if (currentProduct * arr[i] <= k) {
        include = countSubsets(i + 1, currentProduct * arr[i], k, arr);
    }

    return include + exclude;
}

function numOfSubsets(arr, k) {

    // Subtract 1 to exclude the empty subset
    return countSubsets(0, 1, k, arr) - 1;
}

let arr = [1, 2, 3, 4];
let k = 10;
console.log(numOfSubsets(arr, k));

Output
11

Using Top - Down Dp (memoization) - O(n*k) Time and O(n*k) Space

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).

  • There are two parameter that change in the recursive solution: i going from 0 to n-1, currentProduct going from 1 to k. So we create a 2D array of size (n+1)*(k+1) for memoization.
  • We initialize this array as -1 to indicate nothing is computed initially.
  • Now we modify our recursive solution to first check if the value is -1, then only make recursive calls. This way, we avoid re-computations of the same subproblems.
C++
// A C++ program to count the number of subsets
// with a product less than or equal to k memoization
#include <bits/stdc++.h>
using namespace std;

// Recursive function to count subsets whose product is 
// less than or equal to k with memoization
int countSubsets(int i, int currentProduct, int k, 
                 vector<int> &arr, vector<vector<int>> &memo) {
    
    int n = arr.size();

    // Base case: if we have considered all elements
    if (i == n) {
      
        // Return 1 if the current product is less than or
        // equal to k, otherwise 0
        return (currentProduct <= k);
    }

    // Check if the current state is already computed
    if (memo[i][currentProduct] != -1)
        return memo[i][currentProduct];

    // Case 1: Exclude the current element and move to the next
    int exclude = countSubsets(i + 1, currentProduct, k, arr, memo);

    // Case 2: Include the current element in the subset
    int include = 0;
    if ((arr[i] * currentProduct) <= k)
        include = countSubsets(i + 1, currentProduct * arr[i], k, arr, memo);

    // Store the result in the memo table and return the total count
    return memo[i][currentProduct] = (include + exclude);
}

// Wrapper function to calculate the number of subsets
// whose product is less than or equal to k
int numOfSubsets(vector<int> arr, int k) {
    int n = arr.size();

    // Memoization table to store intermediate results
    // Initialized with -1, indicating uncomputed states
    vector<vector<int>> memo(n + 1, vector<int>(k + 1, -1));

    // Call the recursive function starting from index 0
    // Initial product of 1
    // Subtract 1 to exclude the empty subset
    return countSubsets(0, 1, k, arr, memo) - 1;
}

int main() {

    vector<int> arr = {1, 2, 3, 4};
    int k = 10;
    cout << numOfSubsets(arr, k);
    return 0;
}
Java
// A Java program to count the number of subsets
// with a product less than or equal to k memoization
import java.util.Arrays;

class GfG {
   static int countSubsets(int i, int currentProduct, 
                                   int k, int[] arr, int[][] memo) {
        int n = arr.length;

        // Base case: if all elements are considered
        if (i == n) {
            return currentProduct <= k ? 1 : 0;
        }

        // Check if result is already computed
        if (memo[i][currentProduct] != -1) {
            return memo[i][currentProduct];
        }

        // Exclude current element
        int exclude = countSubsets(i + 1, currentProduct, k, arr, memo);

        // Include current element if valid
        int include = 0;
        if (currentProduct * arr[i] <= k) {
            include = countSubsets(i + 1, currentProduct * arr[i], k, arr, memo);
        }

        // Store the result and return
        memo[i][currentProduct] = exclude + include;
        return memo[i][currentProduct];
    }

    static int numOfSubsets(int[] arr, int k) {
        int n = arr.length;
        int[][] memo = new int[n + 1][k + 1];

        // Initialize memoization table
        for (int[] row : memo) {
            Arrays.fill(row, -1);
        }

        // Compute result, subtracting 1 to 
      	// exclude the empty subset
        return countSubsets(0, 1, k, arr, memo) - 1;
    }

    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4};
        int k = 10;
        System.out.println(numOfSubsets(arr, k));
    }
}
Python
# A Python program to count the number of subsets
# with a product less than or equal to k memoization
def countSubsets(i, currentProduct, k, arr, memo):
    n = len(arr)

    # Base case: if all elements are considered
    if i == n:
        return 1 if currentProduct <= k else 0

    # Check if result is already computed
    if memo[i][currentProduct] != -1:
        return memo[i][currentProduct]

    # Exclude current element
    exclude = countSubsets(i + 1, currentProduct, k, arr, memo)

    # Include current element if valid
    include = 0
    if currentProduct * arr[i] <= k:
        include = countSubsets(i + 1, currentProduct * arr[i], k, arr, memo)

    # Store the result and return
    memo[i][currentProduct] = exclude + include
    return memo[i][currentProduct]

def numOfSubsets(arr, k):
    n = len(arr)
    
    # Initialize memoization table
    memo = [[-1] * (k + 1) for _ in range(n + 1)]

    # Compute result, subtracting 1 to exclude 
    # the empty subset
    return countSubsets(0, 1, k, arr, memo) - 1

arr = [1, 2, 3, 4]
k = 10
print(numOfSubsets(arr, k))
C#
// A C# program to count the number of subsets
// with a product less than or equal to k memoization
using System;

class GfG {
    static int CountSubsets(int i, int currentProduct, int k, 
                            int[] arr, int[,] memo) {
        int n = arr.Length;

        // Base case: if all elements are considered
        if (i == n) {
            return currentProduct <= k ? 1 : 0;
        }

        // Check if result is already computed
        if (memo[i, currentProduct] != -1) {
            return memo[i, currentProduct];
        }

        // Exclude current element
        int exclude = CountSubsets(i + 1, currentProduct, k, arr, memo);

        // Include current element if valid
        int include = 0;
        if (currentProduct * arr[i] <= k) {
            include = CountSubsets(i + 1, currentProduct * arr[i], k, arr, memo);
        }

        // Store the result and return
        memo[i, currentProduct] = exclude + include;
        return memo[i, currentProduct];
    }

    static int numOfSubsets(int[] arr, int k) {
        int n = arr.Length;

        // Initialize memoization table
        int[,] memo = new int[n + 1, k + 1];
        for (int i = 0; i <= n; i++) {
            for (int j = 0; j <= k; j++) {
                memo[i, j] = -1;
            }
        }

        // Compute result, subtracting 1 to exclude the empty subset
        return CountSubsets(0, 1, k, arr, memo) - 1;
    }

    static void Main(string[] args) {
        int[] arr = { 1, 2, 3, 4 };
        int k = 10;

        Console.WriteLine(numOfSubsets(arr, k));
    }
}
JavaScript
// A Javascript program to count the number of subsets
// with a product less than or equal to k memoization

function countSubsets(i, currentProduct, k, arr, memo) {
    const n = arr.length;

    // Base case: if all elements are considered
    if (i === n) {
        return currentProduct <= k ? 1 : 0;
    }

    // Check if result is already computed
    if (memo[i][currentProduct] !== -1) {
        return memo[i][currentProduct];
    }

    // Exclude current element
    let exclude = countSubsets(i + 1, currentProduct, k, arr, memo);

    // Include current element if valid
    let include = 0;
    if (currentProduct * arr[i] <= k) {
        include = countSubsets(i + 1, currentProduct * arr[i], k, arr, memo);
    }

    // Store the result and return
    memo[i][currentProduct] = exclude + include;
    return memo[i][currentProduct];
}

function numOfSubsets(arr, k) {
    const n = arr.length;
    const memo = Array.from({ length: n + 1 }, () => Array(k + 1).fill(-1));

    // Compute result, subtracting 1 to exclude the empty subset
    return countSubsets(0, 1, k, arr, memo) - 1;
}

const arr = [1, 2, 3, 4];
const k = 10;
console.log(numOfSubsets(arr, k));

Output
11

Using Dynamic Programming (Tabulation) - O(n*k) Time and O(n*k) Space

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].

C++
// A C++ program to count the number of subsets
// with a product less than or equal to k using tabulation
#include <bits/stdc++.h>
using namespace std;


int numOfSubsets(vector<int> &arr, int k) {
  
    int n = arr.size();

    // Initialize all values of dp[i][j] to 1 to 
  	// include the empty subset.
    vector<vector<int>> dp(n + 1, vector<int>(k + 1, 1));

    for (int i = 1; i <= n; i++) {
      
        for (int j = 1; j <= k; j++) {
          
            // Case 1: Exclude the current element.
            dp[i][j] = dp[i - 1][j];

            // Case 2: Include the current element.
            // if arr[i-1] is less than equal to j we include it.
            if (j >= arr[i - 1]) {
                dp[i][j] += dp[i - 1][j / arr[i - 1]];
            }
        }
    }

    // Return the total count of subsets with product ≤ k, subtracting 1
    // to exclude the empty subset from the result.
    return dp[n][k] - 1;
}

int main() {
  
    vector<int> arr = {1, 2, 3, 4};
    int k = 10;
    cout << numOfSubsets(arr, k);
    return 0;
}
Java
// A Java program to count the number of subsets
// with a product less than or equal to k using tabulation
import java.util.*;

class GfG {
  
   static int numOfSubsets(int[] arr, int k) {
        int n = arr.length;

        // Initialize the DP table with 1s to 
     	// include the empty subset.
        int[][] dp = new int[n + 1][k + 1];
        for (int i = 0; i <= n; i++) {
            Arrays.fill(dp[i], 1);
        }

        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= k; j++) {
              
                // Case 1: Exclude the current element
                dp[i][j] = dp[i - 1][j];

                // Case 2: Include the current element
                if (j >= arr[i - 1]) {
                    dp[i][j] += dp[i - 1][j / arr[i - 1]];
                }
            }
        }

        // Return the total count of subsets
     	// with product ≤ k, subtracting 1
        return dp[n][k] - 1;
    }

    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4};
        int k = 10;

        System.out.println(numOfSubsets(arr, k));
    }
}
Python
# A Python program to count the number of subsets
# with a product less than or equal to k using tabulation
def numOfSubsets(arr, k):
    n = len(arr)

    # Initialize the DP table with 1s to 
    # include the empty subset.
    dp = [[1] * (k + 1) for _ in range(n + 1)]

    for i in range(1, n + 1):
        for j in range(1, k + 1):
            # Case 1: Exclude the current element
            dp[i][j] = dp[i - 1][j]

            # Case 2: Include the current element
            if j >= arr[i - 1]:
                dp[i][j] += dp[i - 1][j // arr[i - 1]]

    # Return the total count of subsets 
    # with product ≤ k, subtracting 1
    return dp[n][k] - 1


arr = [1, 2, 3, 4]
k = 10
print(numOfSubsets(arr, k))
C#
// A C# program to count the number of subsets
// with a product less than or equal to k using tabulation
using System;

class GfG {
   static int numOfSubsets(int[] arr, int k) {
      
        int n = arr.Length;

        // Initialize the DP table with 1s to 
     	// include the empty subset.
        int[,] dp = new int[n + 1, k + 1];
        for (int i = 0; i <= n; i++) {
            for (int j = 0; j <= k; j++) {
                dp[i, j] = 1;
            }
        }

        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= k; j++) {
              
                // Case 1: Exclude the current element
                dp[i, j] = dp[i - 1, j];

                // Case 2: Include the current element
                if (j >= arr[i - 1]) {
                    dp[i, j] += dp[i - 1, j / arr[i - 1]];
                }
            }
        }

        // Return the total count of subsets with
     	// product ≤ k, subtracting 1
        return dp[n, k] - 1;
    }

    static void Main(string[] args) {
        int[] arr = { 1, 2, 3, 4 };
        int k = 10;

        Console.WriteLine(numOfSubsets(arr, k));
    }
}
JavaScript
// A Javascript program to count the number of subsets
// with a product less than or equal to k using tabulation

function numOfSubsets(arr, k) {
    let n = arr.length;

    // Initialize the DP table with 1s to include the empty subset.
    let dp = Array.from({ length: n + 1 }, () => Array(k + 1).fill(1));

    for (let i = 1; i <= n; i++) {
        for (let j = 1; j <= k; j++) {
        
            // Case 1: Exclude the current element
            dp[i][j] = dp[i - 1][j];

            // Case 2: Include the current element
            if (j >= arr[i - 1]) {
                dp[i][j] += dp[i - 1][Math.floor(j / arr[i - 1])];
            }
        }
    }

    // Return the total count of subsets 
    // with product ≤ k, subtracting 1
    return dp[n][k] - 1;
}

let arr = [1, 2, 3, 4];
let k = 10;
console.log(numOfSubsets(arr, k));

Output
11

Using Space Optimised DP - O(n*k) Time and O(k) Space

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;

C++
// A C++ program to count the number of subsets
// with a product less than or equal to k 
// using space-optimized tabulation.

#include <bits/stdc++.h>
using namespace std;

// Function to count subsets with product less than or equal to k
int numOfSubsets(vector<int> &arr, int k) {

    int n = arr.size();

    // Initialize two arrays to store the previous and current state
    // Both initialized with 1 to include the empty subset
    vector<int> prevState(k + 1, 1), curState(k + 1, 1);

    for (int i = 1; i <= n; i++) {
      
        // Copy the previous state to the current state
        curState = prevState;

        for (int j = 1; j <= k; j++) {
          
            // If the current element can be included in subsets
            // Add the count of subsets ending at the previous element
            // where the product multiplied by the current element is ≤ k
            if (j >= arr[i - 1]) {
                curState[j] += prevState[j / arr[i - 1]];
            }
        }

        // Update the previous state for the next iteration
        prevState = curState;
    }

    // Return the total count of subsets with product ≤ k, subtracting 1
    // to exclude the empty subset
    return curState[k] - 1;
}

int main() {

    vector<int> arr = {1, 2, 3, 4};
    int k = 10;
    cout << numOfSubsets(arr, k);
    return 0;
}
Java
// A Java program to count the number of subsets
// with a product less than or equal to k 
// using space-optimized tabulation.

import java.util.Arrays;

class GfG {

    static int numOfSubsets(int[] arr, int k) {
        int n = arr.length;

        // Initialize two arrays for previous and current states
        int[] prevState = new int[k + 1];
        int[] curState = new int[k + 1];
        Arrays.fill(prevState, 1);
        Arrays.fill(curState, 1);

        for (int i = 1; i <= n; i++) {
          
            // Copy previous state to current state
            curState = Arrays.copyOf(prevState, k + 1);

            for (int j = 1; j <= k; j++) {
                // Include current element if valid
                if (j >= arr[i - 1]) {
                    curState[j] += prevState[j / arr[i - 1]];
                }
            }

            // Update previous state
            prevState = curState;
        }

        // Subtract 1 to exclude the empty subset
        return curState[k] - 1;
    }

    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4};
        int k = 10;
        System.out.println(numOfSubsets(arr, k));
    }
}
Python
# A Python program to count the number of subsets
# with a product less than or equal to k 
# using space-optimized tabulation.

def numOfSubsets(arr, k):
    n = len(arr)

    # Initialize previous and current state arrays
    prevState = [1] * (k + 1)
    curState = [1] * (k + 1)

    for i in range(1, n + 1):
      
        # Copy previous state to current state
        curState = prevState[:]

        for j in range(1, k + 1):
          
            # Include current element if valid
            if j >= arr[i - 1]:
                curState[j] += prevState[j // arr[i - 1]]

        # Update previous state
        prevState = curState

    # Subtract 1 to exclude the empty subset
    return curState[k] - 1


arr = [1, 2, 3, 4]
k = 10
print(numOfSubsets(arr, k))
C#
// A C# program to count the number of subsets
// with a product less than or equal to k 
// using space-optimized tabulation.
using System;

class GfG {

   static int numOfSubsets(int[] arr, int k) {
        int n = arr.Length;

        // Initialize previous and current 
     	// state arrays
        int[] prevState = new int[k + 1];
        int[] curState = new int[k + 1];
        Array.Fill(prevState, 1);
        Array.Fill(curState, 0);

        for (int i = 0; i < n; i++) {
          
            // Copy previous state to current 
          	// state for this iteration
            Array.Copy(prevState, curState, k + 1);

            for (int j = 1; j <= k; j++) {
              
                // Include the current element if
              	// it can be part of a subset
                if (j >= arr[i]) {
                    curState[j] += prevState[j / arr[i]];
                }
            }

            // Update previous state for the 
          	// next iteration
            Array.Copy(curState, prevState, k + 1);
        }

        // Subtract 1 to exclude the empty 
     	// subset from the result
        return curState[k] - 1;
    }

    static void Main(string[] args) {
        int[] arr = { 1, 2, 3, 4 };
        int k = 10;
        Console.WriteLine(numOfSubsets(arr, k)); 
    }
}
JavaScript
// A Javascript program to count the number of subsets
// with a product less than or equal to k 
// using space-optimized tabulation.

function numOfSubsets(arr, k) {
    let n = arr.length;

    // Initialize previous and current state arrays
    let prevState = Array(k + 1).fill(1);
    let curState = Array(k + 1).fill(1);

    for (let i = 1; i <= n; i++) {
    
        // Copy previous state to current state
        curState = [...prevState];

        for (let j = 1; j <= k; j++) {
        
            // Include current element if valid
            if (j >= arr[i - 1]) {
                curState[j] += prevState[Math.floor(j / arr[i - 1])];
            }
        }

        // Update previous state
        prevState = curState;
    }

    // Subtract 1 to exclude the empty subset
    return curState[k] - 1;
}

let arr = [1, 2, 3, 4];
let k = 10;
console.log(numOfSubsets(arr, k));

Output
11

Related article:

Comment