Number of subsets with product less than k using DP (original) (raw)

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.

Table of Content

**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:

I**nclude the current element: The current element is **included in the subset, and the product is updated as **currentProduct * arr[i]. This corresponds to:

**Recurrence relation:

**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 &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& 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));

`

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

// 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 &arr, vector<vector> &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 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));

`

**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 productvalue less than equal to j from subsets of arr[0...i-1].

We fill the dp array as following:

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 productvalue 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 &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));

`

**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 &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));

`

**Related article: