Count Subarrays with a Specified Average Value
This article will tackle a problem involving subarrays and arithmetic means, aiming to develop an efficient solution. So, lets explore how to efficiently count subarrays with a specified average value in Java. The problem is defined as follows:
1. Problem Statement
Given an array X
and an integer S
, find how many contiguous subarrays of X
have an arithmetic mean equal to S
. For instance, given X = [5, 3, 6, 2]
and S = 4
, the result is 3. The subarrays [5, 3]
, [6, 2]
, and [5, 3, 6, 2]
all have an arithmetic mean of 4.
The array X
can have up to 100,000 elements, and each element in X
is an integer within the range [-1,000,000,000, +1,000,000,000]
. Similarly, the target S
can also be a large integer. Therefore, efficiency is crucial.
2. Brute Force Approach
We can start with a brute-force solution, which works by iterating over all possible subarrays and calculating their arithmetic mean. This solution works for small datasets but becomes inefficient for larger arrays.
public class BruteForceMeanSubarrays { public static int returnSubsequenceCount(int[] X, int S) { int counter = 0; for (int i = 0; i < X.length; i++) { int[] dpSum = new int[X.length]; // Dynamic programming array to store the sum of subarrays dpSum[i] = X[i]; // Initialize with the current element if (X[i] == S) { // Check if the current element is equal to the target mean counter++; } for (int j = i + 1; j < X.length; j++) { int sum = dpSum[j - 1] + X[j]; // Calculate sum of subarray from i to j dpSum[j] = sum; // Store the subarray sum // Check if the mean of the subarray equals S if ((double) sum / (j - i + 1) == S) { counter++; } } } return counter; } public static void main(String[] args) { int[] X = {5, 3, 6, 2}; int S = 4; int result = returnSubsequenceCount(X, S); System.out.println("Number of subarrays with mean " + S + ": " + result); } }
Here is how it works:
- We initialize a counter to keep track of valid subarrays.
- For every starting index
i
, we calculate the sum of all subarrays starting ati
using a dynamic programming arraydpSum[]
. - If the arithmetic mean (i.e.,
sum / length_of_subarray
) equalsS
, we increment the counter.
Output:
Number of subarrays with mean 4: 3
2.1 Limitations
While this solution works for small arrays, its time complexity is O(n²)
because we calculate sums for every subarray starting from every index. This becomes inefficient when n
(length of the array) reaches up to 100,000.
3. Optimized Approach
The brute-force approach is simple but becomes inefficient with large datasets. With a time complexity of O(n²), the algorithm slows down significantly as the array size increases. For arrays with up to 100,000 elements, we need a more efficient solution to handle the computation within a reasonable time.
To do this, we can use the idea of prefix sums, reducing the time complexity to O(n). This optimized approach makes use of a hash map to track the number of times each prefix sum appears, allowing us to count valid subarrays efficiently.
public class OptimizedArithmeticMeanSubarrays { public static int countSubarraysWithMean(int[] X, int S) { Map<Long, Integer> prefixSumCount = new HashMap<>(); long sum = 0; // Running sum of the array elements int count = 0; // Base case: A prefix sum of 0 occurs once (to account for subarrays starting from index 0) prefixSumCount.put(0L, 1); for (int i = 0; i < X.length; i++) { sum += X[i]; // Update the running sum // Calculate the required sum for the subarray's arithmetic mean to equal S long requiredSum = sum - (long) S * (i + 1); // If the required sum exists in the prefix map, count the valid subarrays if (prefixSumCount.containsKey(requiredSum)) { count += prefixSumCount.get(requiredSum); } // Update the prefix sum map prefixSumCount.put(sum - (long) S * (i + 1), prefixSumCount.getOrDefault(sum - (long) S * (i + 1), 0) + 1); } return count; } public static void main(String[] args) { int[] X = {5, 3, 6, 2}; int S = 4; int result = countSubarraysWithMean(X, S); System.out.println("Number of subarrays with mean " + S + ": " + result); } }
The countSubarraysWithMean
method takes an integer array X
and an integer S
as parameters, initializing a hash map, prefixSumCount
, to store adjusted prefix sums for efficient counting of valid subarrays. A long
variable sum
tracks the running total, while an integer variable count
records valid subarrays, starting with an entry of 0
mapped to 1
. As the method iterates through X
, it updates the running sum, calculates the requiredSum
by subtracting S * (i + 1)
, checks if requiredSum
exists in the map to update the count, and adds the adjusted prefix sum to the hash map.
Output:
4. Conclusion
In this article, we looked at how to count contiguous subarrays with a specific arithmetic mean. We started with a simple but slow method and then presented a faster approach using prefix sums and a hash map. This optimized method helps efficiently find valid subarrays, even in large datasets, offering a clear solution to the problem.
5. Download the Source Code
This article covers how to count subarrays with a specified average value in Java.
You can download the full source code of this example here: java count subarrays specified average value