Count Subarrays With Fixed Bounds

Updated on 12 May, 2025
Count Subarrays With Fixed Bounds header image

Problem Statement

In this task, you are working with an integer array called nums, alongside two specific integers minK and maxK. Your goal is to count how many contiguous subarrays (sections of the original array) meet the following two criteria:

  • The smallest number in the subarray is exactly minK.
  • The largest number in the subarray is exactly maxK.

A subarray is considered a continuous portion or slice of the original array. Counting the exact number of these "fixed-bound subarrays" will be your primary objective.

Examples

Example 1

Input:

nums = [1,3,5,2,7,5], minK = 1, maxK = 5

Output:

2

Explanation:

The fixed-bound subarrays are [1,3,5] and [1,3,5,2].

Example 2

Input:

nums = [1,1,1,1], minK = 1, maxK = 1

Output:

10

Explanation:

Every subarray of nums is a fixed-bound subarray. There are 10 possible subarrays.

Constraints

  • 2 <= nums.length <= 105
  • 1 <= nums[i], minK, maxK <= 106

Approach and Intuition

Given the problem and its constraints, let's dissect how we might approach finding the fixed-bound subarrays:

  1. Understanding the Subarray Condition: A valid subarray is defined not just by its contents but by making sure its minimum and maximum values align perfectly with minK and maxK. This indicates that any valid subarray must contain both minK and maxK and all values between them must not exceed maxK or drop below minK.

  2. Traversing the Array:

    • We might consider traversing the array and dynamically checking each potential starting point for subarrays that could meet the conditions. As we extend our subarray, if we encounter a value outside the [minK, maxK] range, we can immediately stop considering this segment as it no longer meets the condition.
  3. Using Two Pointers or Sliding Window:

    • A sliding window or two-pointer approach might be efficient here. Initiate two pointers, say start and end representing the beginning and the end of a potential subarray. Move end to expand the window and include more elements. As you move end over the array elements:
      • Continuously check and update the current minimum and maximum of the elements within the window.
      • If these values match minK and maxK, then every extension of this window from position start to end (while maintaining the min and max) is a valid subarray.
      • If a value outside the desired range is included as end progresses, reset start to just beyond this point and begin the search anew.
  4. Counting the Subarrays:

    • Each time the conditions are met (current min is minK, and current max is maxK), count the subarray. Adjust the count based on the number of new subarrays formed by extending end while keeping start fixed.
  5. Optimization by Breaking Early:

    • Due to the property of subarrays, once a value that invalidates the max/min condition is encountered at end, any further extensions will also be invalid until start is adjusted. This helps in reducing unnecessary checks.

By following this approach, we can efficiently check each segment of the array for being a "fixed-bound subarray" without redundantly re-checking every possible subarray combination, thus optimizing the overall process.

Solutions

  • C++
  • Java
  • Python
cpp
class Solution {
public:
    long long countValidSubarrays(vector<int>& arr, int minVal, int maxVal) {
        long long result = 0;
        int lastMin = -1, lastMax = -1, lastInvalid = -1;
        
        for (int idx = 0; idx < arr.size(); ++idx) {
            if (arr[idx] < minVal || arr[idx] > maxVal)
                lastInvalid = idx;
            
            if (arr[idx] == minVal) 
                lastMin = idx;
            if (arr[idx] == maxVal)
                lastMax = idx;

            result += max(0, min(lastMax, lastMin) - lastInvalid);
        }
        return result;
    }
};

This C++ solution for the problem "Count Subarrays With Fixed Bounds" effectively counts all subarrays within an array that meet particular boundary criteria.

  • Step to understand approach:

    1. Initialize counters to track occurrences and positions:
      • lastMin: Tracks the last position where the minimum value (minVal) was found.
      • lastMax: Tracks the last position where the maximum value (maxVal) was found.
      • lastInvalid: Tracks the last position of an element that is outside the bounding values.
    2. Loop through each element of the input vector. For each index:
      • Update lastInvalid if the current element does not lie between minVal and maxVal.
      • Update lastMin if the element is equal to minVal.
      • Update lastMax if the element is equal to maxVal.
    3. Calculate the valid subarrays by comparing the positions of lastMin, lastMax, and lastInvalid. Add to the result the number of new valid subarrays that include the current element, which should be at least zero in cases where lastMin or lastMax occurs after lastInvalid.
  • Key components:

    • Using the maximum of zero ensures that only valid positions contribute to the count.
    • max function is used to ensure the result is always non-negative, preventing negative counts in scenarios where lastMin or lastMax have not yet been initialized properly before an invalid value.

With these steps, the code efficiently calculates the number of valid subarrays where the values meet the requirements of containing both a minVal and a maxVal without violations, handling edge cases involving elements outside the specified bounds seamlessly.

java
class Solution {
    public long calculateValidSubarrays(int[] elements, int lowerBound, int upperBound) {
        long subarrayCount = 0;
        int minPos = -1, maxPos = -1, lastInvalid = -1;

        for (int idx = 0; idx < elements.length; ++idx) {
            if (elements[idx] < lowerBound || elements[idx] > upperBound)
                lastInvalid = idx;

            if (elements[idx] == lowerBound)
                minPos = idx;
            if (elements[idx] == upperBound)
                maxPos = idx;

            subarrayCount += Math.max(0, Math.min(maxPos, minPos) - lastInvalid);
        }
        return subarrayCount;
    }
}

The provided Java program defines a method calculateValidSubarrays that counts the number of subarrays in a given array of integers where all elements fit within a specified range, defined by lowerBound and upperBound. Here’s how it works:

  • Initialize subarrayCount to count valid subarrays and three pointers minPos, maxPos, and lastInvalid to -1. These pointers track the positions of the minimum value, maximum value, and the most recent element outside the valid range, respectively.
  • Iterate over the input array using an index idx.
  • If the current element is outside the valid range, update lastInvalid to the current index idx.
  • If the current element equals the lowerBound, update minPos to the current index.
  • Similarly, if the current element equals the upperBound, update maxPos to the current index.
  • Increment the subarrayCount by the difference between the smallest of maxPos or minPos and lastInvalid, making sure this difference is not negative.

The method finally returns the total count of subarrays that satisfy the conditions of having all elements between the lowerBound and upperBound. Ensure to invoke this method by passing a valid array and appropriate bounds to get the count of valid subarrays.

python
class Solution:
    def validSubarrayCount(self, data: List[int], lower: int, upper: int) -> int:
        res = 0
        low_idx = high_idx = last_invalid = -1
        
        for idx, val in enumerate(data):
            if val < lower or val > upper:
                last_invalid = idx

            if val == lower:
                low_idx = idx
            if val == upper:
                high_idx = idx

            res += max(0, min(low_idx, high_idx) - last_invalid)

        return res

This Python program counts the number of subarrays in a given list data that have all elements within a specified range (lower to upper). It efficiently assesses each element's relation to this range and adjusts indices to tally valid subarrays. Here's how it works:

  • Initialize counters and indices: res for the count of valid subarray, low_idx, high_idx for tracking the last occurrences of the lower and upper bounds respectively, and last_invalid for the most recent index of an out-of-bounds element.
  • Iterate over the array using a loop. For each element and its index:
    • Check if the element is out of the desired range, updating last_invalid if it is.
    • Update low_idx if the element matches lower.
    • Update high_idx if the element matches upper.
    • Increase res based on the positions of low_idx, high_idx, and last_invalid, calculating possible subarray indices that satisfy the bounds.

Through this method, the code effectively tallies all subarrays where the bounds are respected, ensuring no subarrays include invalid elements outside the specified range. This approach not only keeps track of valid subarray indices but also efficiently excludes invalid sequences without manual checks of subarray contents.

Comments

No comments yet.