LeetCode 2302: Count Subarrays With Score Less Than K

Difficulty: Hard
Topics: Arrays, Sliding Window
Companies: Google, Amazon, Meta
Pro Tip: This problem is an excellent example of when to use the sliding window technique for optimizing subarray calculations. Mastering this pattern will help you solve many array manipulation problems efficiently.

The problem "Count Subarrays With Score Less Than K" (LeetCode 2302) requires us to count the number of non-empty subarrays where the product of the subarray's sum and its length is strictly less than a given integer k. This problem tests our ability to optimize subarray calculations and is a classic example of when the sliding window technique shines.

Problem Statement

The score of an array is defined as the product of its sum and its length.

Given a positive integer array nums and an integer k, return the number of non-empty subarrays of nums whose score is strictly less than k.

A subarray is a contiguous sequence of elements within an array.

score = (sum of subarray elements) × (length of subarray)

Constraints

Problem Link

View on LeetCode ↗

Example 1

Input: nums = [2,1,4,3,5], k = 10
Output: 6
Explanation:
The 6 subarrays having scores less than 10 are:
- [2] → score = 2 × 1 = 2
- [1] → 1 × 1 = 1
- [4] → 4 × 1 = 4
- [3] → 3 × 1 = 3
- [5] → 5 × 1 = 5
- [2,1] → (2+1) × 2 = 6
Note that subarrays like [1,4] and [4,3,5] have scores of 10 and 36 respectively,
which are not less than 10.

Example 2

Input: nums = [1,1,1], k = 5
Output: 5
Explanation:
Every subarray except [1,1,1] has a score less than 5:
- [1] → 1 × 1 = 1
- [1] → 1 × 1 = 1
- [1] → 1 × 1 = 1
- [1,1] → (1+1) × 2 = 4
- [1,1] → (1+1) × 2 = 4
The subarray [1,1,1] has score (1+1+1) × 3 = 9, which is not less than 5.
Note: Since all elements are positive, longer subarrays will generally have higher scores, which is why we can optimize using the sliding window approach.

Approach 1: Brute Force (TLE)

The brute force approach checks every possible subarray and calculates its score. While straightforward, this approach results in O(n²) time complexity, which is too slow for the upper constraint of n ≤ 10⁵.

Algorithm Steps

  1. Initialize a counter to zero
  2. Iterate through all possible starting indices
  3. For each starting index, expand the subarray to the right
  4. Calculate the score for each subarray
  5. Increment counter if score < k
  6. Break early if score ≥ k (since longer subarrays will have higher scores)
  7. Return the final count

Complexity Analysis

Time Complexity Space Complexity
O(n²) O(1)

Why it fails: For n = 105, the number of operations would be around 1010, which is way beyond what's acceptable (typically need to stay under 106 operations).

Implementation


class Solution {
public:
    long long countSubarrays(vector<int>& nums, long long k) {
        int n = nums.size();
        long long count = 0;
        
        for(int i = 0; i < n; i++) {
            long long sum = 0;
            for(int j = i; j < n; j++) {
                sum += nums[j];
                long long score = sum * (j - i + 1);
                
                if(score < k) {
                    count++;
                } else {
                    break; // Longer subarrays will have higher scores
                }
            }
        }
        
        return count;
    }
};
                

class Solution {
    public long countSubarrays(int[] nums, long k) {
        int n = nums.length;
        long count = 0;
        
        for(int i = 0; i < n; i++) {
            long sum = 0;
            for(int j = i; j < n; j++) {
                sum += nums[j];
                long score = sum * (j - i + 1);
                
                if(score < k) {
                    count++;
                } else {
                    break; // Longer subarrays will have higher scores
                }
            }
        }
        
        return count;
    }
}
                

class Solution:
    def countSubarrays(self, nums: List[int], k: int) -> int:
        n = len(nums)
        count = 0
        
        for i in range(n):
            current_sum = 0
            for j in range(i, n):
                current_sum += nums[j]
                score = current_sum * (j - i + 1)
                
                if score < k:
                    count += 1
                else:
                    break  # Longer subarrays will have higher scores
                    
        return count
                
Note: This solution will result in Time Limit Exceeded (TLE) for large inputs due to its O(n²) time complexity.

Approach 2: Sliding Window (Optimal)

The optimal solution uses a sliding window technique to maintain a window where the score is less than k. This approach works because with positive numbers, expanding the window increases the score, and shrinking it decreases the score.

Key Insights

Algorithm Steps

  1. Initialize left pointer, sum, and count to 0
  2. Iterate with right pointer from 0 to n-1
  3. Add nums[right] to the current sum
  4. While score (sum × window length) ≥ k:
    • Subtract nums[left] from sum
    • Move left pointer forward
  5. Add window length to count (all subarrays ending at right)
  6. Return the total count

Complexity Analysis

Time Complexity Space Complexity
O(n) O(1)

Explanation: Each element is processed exactly twice (added once when window expands and removed once when window contracts), resulting in O(n) time complexity.

Implementation


class Solution {
public:
    long long countSubarrays(vector<int>& nums, long long k) {
        long long count = 0;
        long long sum = 0;
        int left = 0;
        int n = nums.size();
        
        for(int right = 0; right < n; right++) {
            sum += nums[right];
            
            // Shrink the window from left while condition is invalid
            while(sum * (right - left + 1) >= k) {
                sum -= nums[left];
                left++;
            }
            
            // All subarrays ending at 'right' with start >= left are valid
            count += (right - left + 1);
        }
        
        return count;
    }
};
                

class Solution {
    public long countSubarrays(int[] nums, long k) {
        long count = 0;
        long sum = 0;
        int left = 0;
        int n = nums.length;
        
        for(int right = 0; right < n; right++) {
            sum += nums[right];
            
            // Shrink the window from left while condition is invalid
            while(sum * (right - left + 1) >= k) {
                sum -= nums[left];
                left++;
            }
            
            // All subarrays ending at 'right' with start >= left are valid
            count += (right - left + 1);
        }
        
        return count;
    }
}
                

class Solution:
    def countSubarrays(self, nums: List[int], k: int) -> int:
        count = 0
        current_sum = 0
        left = 0
        
        for right in range(len(nums)):
            current_sum += nums[right]
            
            # Shrink the window from left while condition is invalid
            while current_sum * (right - left + 1) >= k:
                current_sum -= nums[left]
                left += 1
                
            # All subarrays ending at 'right' with start >= left are valid
            count += (right - left + 1)
            
        return count
                
Why This Works: For each right pointer, we find the smallest left such that the window [left..right] has score < k. All subarrays ending at right with start ≥ left are valid, and there are exactly (right - left + 1) of them.

Edge Cases and Special Considerations

When implementing solutions for this problem, consider these edge cases:

1. Single Element Arrays

Input: nums = [5], k = 10
Output: 1 (5 × 1 = 5 < 10)

Input: nums = [10], k = 5
Output: 0 (10 × 1 = 10 ≥ 5)

2. All Elements Equal

Input: nums = [2,2,2,2], k = 10
Output: 4
[2]×1=2, [2]×1=2, [2]×1=2, [2]×1=2
No subarrays of length ≥2 have score < 10:
[2,2]×2=8, [2,2,2]×3=18, etc.

3. Large k Values

Input: nums = [1,2,3,...,100000], k = 1015
Output: n*(n+1)/2 ≈ 5×109 (all possible subarrays)
Must handle large counts efficiently

4. Minimum/Maximum Values

Input: nums = [1,1,1,...,1] (105 elements), k = 2
Output: 105 (only single-element subarrays qualify)
Important: Always test with the upper constraint limits (n=10⁵) to ensure your solution handles large inputs efficiently.

Comparison of Approaches

Approach Time Complexity Space Complexity When to Use Pros Cons
Brute Force O(n²) O(1) Small inputs (n < 1000) Simple to implement Fails for large n
Sliding Window O(n) O(1) All cases, especially large n Optimal for constraints Slightly more complex logic
Interview Tip: When you see subarray problems with positive numbers and product/sum conditions, the sliding window technique should be your first thought. This pattern is common in coding interviews.

Frequently Asked Questions

1. Why does the sliding window approach work for this problem?

The sliding window approach works because all numbers are positive. This means that expanding the window always increases the score (sum × length), and shrinking the window always decreases it. This monotonic property allows us to efficiently find valid windows by adjusting the left pointer.

2. Would this solution work if the array contained negative numbers?

No, the sliding window approach wouldn't work directly with negative numbers because expanding the window could potentially decrease the sum (and thus the score). For arrays with negative numbers, we would need a different approach like prefix sums with a hash map.

3. How does the count += (right - left + 1) work?

This counts all valid subarrays ending at the current right pointer. For a window [left..right], there are exactly (right - left + 1) subarrays ending at right: [left..right], [left+1..right], ..., [right..right].

4. What's the space complexity of the optimal solution?

The space complexity is O(1) because we only use a constant amount of additional space (for variables like sum, count, left, right) regardless of the input size.

5. Can this problem be solved using prefix sums?

While prefix sums could help calculate subarray sums quickly, they wouldn't directly help with the score calculation (sum × length) or the sliding window optimization. The sliding window approach is more suitable for this specific problem.

6. How would you modify the solution if the condition was ≤ k instead of < k?

We would simply change the while loop condition from >= k to > k. This would make the window include subarrays with score equal to k in our count.

7. What's the best way to test this code?

Test with: single-element arrays, all elements equal, strictly increasing/decreasing arrays, minimum/maximum values, and the upper constraint limits. Also verify edge cases where k is very small or very large compared to array values.

8. Is there a mathematical formula to solve this without iteration?

No general formula exists because the solution depends on the specific values in the array. The sliding window approach is optimal for this problem with O(n) time complexity.

9. How does this problem relate to real-world applications?

Similar algorithms are used in data streaming applications where we need to monitor subsets of data that meet certain statistical criteria (like average × duration below a threshold). It's also useful in financial analysis for finding periods with certain performance metrics.

10. What similar problems should I practice to master this pattern?

Recommended problems: 209 (Minimum Size Subarray Sum), 713 (Subarray Product Less Than K), 904 (Fruit Into Baskets), 1004 (Max Consecutive Ones III), and 1658 (Minimum Operations to Reduce X to Zero). These all use variations of the sliding window technique.

Final Thoughts: This problem beautifully demonstrates the power of the sliding window technique for optimizing subarray calculations. The key insight is recognizing that with positive numbers, window expansion and contraction have predictable effects on the score. Mastering this pattern will help you solve many array manipulation problems efficiently.