Subarray Product Less Than K

Updated on 07 July, 2025
Subarray Product Less Than K header image

Problem Statement

The goal is to determine how many contiguous subarrays (a sequence of elements that are adjacent in the array) from an integer array nums have a product of their elements that is less than a given integer k. The solution requires efficient computation as the size of the array can be as large as 30,000 elements, and the elements themselves can range up to 1,000. The value of k can be as large as 1,000,000. We need to count every possible subarray where the cumulative product of its elements is strictly less than k.

Examples

Example 1

Input:

nums = [10,5,2,6], k = 100

Output:

8

Explanation:

The 8 subarrays that have product less than 100 are:
[10], [5], [2], [6], [10, 5], [5, 2], [2, 6], [5, 2, 6]
Note that [10, 5, 2] is not included as the product of 100 is not strictly less than k.

Example 2

Input:

nums = [1,2,3], k = 0

Output:

0

Constraints

  • 1 <= nums.length <= 3 * 104
  • 1 <= nums[i] <= 1000
  • 0 <= k <= 106

Approach and Intuition

The problem essentially explores how many sub-segments of an array multiply to a value below a certain threshold. Here’s a step-by-step breakdown on how we might tackle this:

  1. Sliding Window Technique:

    • Since we are looking for product of contiguous elements, one efficient strategy is to use a sliding window approach. This facilitates dynamically adjusting the size of the subarray to either include or exclude elements to satisfy the product condition (less than k).
  2. Two Pointer Approach:

    • Use two pointers named start and end to represent our current window of subarrays. The end pointer will expand the window by moving to the right and including more elements, while the start pointer will contract the window from the left when the product condition exceeds k.
  3. Maintain Running Product:

    • As the end pointer includes more elements, multiply these elements to a running product. If at any point, this product meets or exceeds k, the start pointer needs to adjust by moving right, dividing out the leftmost element of our window from the product, until the product is again less than k.
  4. Counting Valid Subarrays:

    • Every time we add a new element to the current window (every move of the end pointer) which keeps the product less than k, all subarrays ending at the current end but starting from current start to end are valid. The number of these is end - start + 1.

Example Walk-through (from provided inputs):

For nums = [10, 5, 2, 6], k = 100:

  • Start with end = 0 and start = 0 with product = 10 which is less than 100. The valid subarray is [10].
  • Move end to 1, product = 50. Still valid. New subarrays: [10, 5], [5].
  • And so on, expanding the sliding window as we confirm the product remains valid.

This approach ensures that we efficiently find all subarrays that meet the conditions without having to reevaluate each possible subarray from scratch.

Solutions

  • C++
cpp
class Solution {
public:
    int countSubarraysWithProductLessThanK(vector<int>& arr, int threshold) {
        if (threshold <= 1) return 0;
        double logThreshold = log(threshold);
        int n = arr.size() + 1;
        vector<double> logAccum(n);
    
        // Preparing prefix sum for logarithms
        for (int i = 0; i < arr.size(); i++) {
            logAccum[i + 1] = logAccum[i] + log(arr[i]);
        }
    
        int resultCount = 0;
        // Addressing through each possible subarray starting index
        for (int start = 0; start < n; start++) {
            int left = start + 1, right = n;
            while (left < right) {
                int mid = left + (right - left) / 2;
                if (logAccum[mid] < logAccum[start] + logThreshold - 1e-9) {
                    left = mid + 1;
                } else {
                    right = mid;
                }
            }
            resultCount += left - start - 1;
        }
        return resultCount;
    }
};

The provided C++ solution focuses on the problem of finding the number of subarrays where the product of their elements is less than a given threshold. The solution employs an efficient algorithm leveraging logarithmic properties to simplify multiplicative comparisons into additive ones.

Here's an overview of the approach used:

  • First, handle the edge case by checking if the threshold is less than or equal to 1. If so, there are no valid subarrays, and the function returns 0.

  • Convert the threshold into its logarithmic form (logThreshold), which will be used for comparison. This step is significant because dealing with sums of logarithms is more straightforward than dealing with products directly due to their additive properties.

  • Calculate and store cumulative logarithmic sums (logAccum) of the array elements. These serve as prefix sums but in the logarithmic domain and are used to calculate the product of any subarray rapidly.

  • Iterate over all possible starting indices of subarrays (start). For each starting index, use a binary search mechanism to find the maximum end index such that the product of the subarray from the current start to this end index is less than the threshold.

  • The binary search checks if the difference between logAccum at mid and start indices is less than logThreshold. By adjusting left and right pointers based on this condition, the appropriate subarray end index is located.

  • Accumulate the count of valid subarrays (resultCount) by computing the difference between the appropriate end index and the current start index.

This approach effectively reduces the problem complexity by transforming the product comparisons into sum comparisons, utilizing logarithmic properties, which are computationally more efficient to handle in a binary search setting. This makes the solution highly efficient even for large input sizes or smaller thresholds.

  • Java
java
class Solution {
    public int countSubarraysWithProductLessThanK(int[] elements, int threshold) {
        if (threshold == 0) return 0;
        double logThreshold = Math.log(threshold);
        int size = elements.length + 1;
        double[] prefixSumLogs = new double[size];
            
        // Calculating prefix sums of logarithms of array elements
        for (int i = 0; i < elements.length; i++) {
            prefixSumLogs[i + 1] = prefixSumLogs[i] + Math.log(elements[i]);
        }
    
        int resultCount = 0;
        // Counting the subarrays that have a product less than the threshold
        for (int start = 0; start < size; start++) {
            int low = start + 1, high = size;
            while (low < high) {
                int mid = low + (high - low) / 2;
                if (prefixSumLogs[mid] < prefixSumLogs[start] + logThreshold - 1e-9) {
                    low = mid + 1;
                } else {
                    high = mid;
                }
            }
            resultCount += low - start - 1;
        }
        return resultCount;
    }
}

Problem Summary: The task is to find the count of all contiguous subarrays within an array where the product of elements is less than a provided threshold, K. The code is written in Java.

Solution Approach:

  1. Initialize a condition to handle the scenario where the threshold K is zero since any product with this threshold would be impossible unless the array is empty.
  2. Calculate the natural logarithm of the threshold to transform multiplicative comparisons into additive ones, improving the efficiency.
  3. Prepare an array prefixSumLogs to store the prefix cumulative sums of the logarithms of the array elements. This transformation simplifies the product of elements into a sum of logs, which is computationally advantageous.
  4. Iterate over possible starting indices of subarrays and use binary search within the logarithm prefix sums to quickly identify how far the subarray can extend before exceeding the logarithmic threshold.
  5. Accumulate the count of valid subarrays that satisfy the product condition for each starting index.

Key Operations:

  • Calculation of logarithms for threshold and array elements.
  • Use of prefix sum to efficiently calculate subarray sums.
  • Utilization of binary search to optimize the identification of valid subarray bounds.

Outcome: The result is the count of subarrays where the product of their elements is less than the given threshold K. This approach efficiently handles the problem with a combination of logarithmic transformation, prefix sum, and binary search techniques.

  • Python
python
class Solution:
    def countSubarraysWithLessProduct(self, numbers: List[int], threshold: int) -> int:
        if threshold <= 0:
            return 0
        logarithm_threshold = math.log(threshold)
    
        # Prefix sums using logarithms to handle product
        prefix_logarithms = [0]
        for number in numbers:
            prefix_logarithms.append(prefix_logarithms[-1] + math.log(number))
    
        subsequences_count = 0
        # Searching with binary search to find valid subarrays
        for start in range(len(prefix_logarithms)):
            low, high = start + 1, len(prefix_logarithms)
            while low < high:
                mid = (low + high) // 2
                if prefix_logarithms[mid] < prefix_logarithms[start] + logarithm_threshold - 1e-9:
                    low = mid + 1
                else:
                    high = mid
            subsequences_count += low - start - 1
    
        return subsequences_count

The code provided defines a method to find the number of contiguous subarrays whose product of elements is less than a specified threshold. Here you'll learn how to understand the solution implemented in Python for calculating these subarrays:

  • Initialize the countSubarraysWithLessProduct method in the Solution class which takes an array of integers numbers and an integer threshold.
  • First, check if the threshold is less than or equal to 0. If true, return 0 since no product can be less than or equal to 0.
  • Convert the threshold into its logarithmic form using the natural logarithm for easier multiplication handling (since logarithm converts multiplications into additions).
  • Prepare an array prefix_logarithms to store the cumulative sums of logarithms of the array elements. This transformation aids in using the properties of logarithms to multiply numbers by adding their logarithms.
  • Initialize a counter subsequences_count to keep track of the valid subarrays.
  • Use binary search on the array of prefix logarithms to efficiently find the length of subarrays that meet the condition where the product is less than the threshold. This is achieved by comparing sums of logarithms.
  • Iterate over each possible starting point of subarrays, then use binary search to find how far the product of the subarray remains below the threshold.
  • Increment the subsequences_count by the number of valid positions identified from the binary search.
  • Return the total count of such subarrays.

This code uses logarithms to transform the product constraint into a sum comparison problem, and binary search to efficiently count subarrays that satisfy the product condition, resulting in an effective method to solve the problem.

Comments

No comments yet.