Count Number of Nice Subarrays

Updated on 09 May, 2025
Count Number of Nice Subarrays header image

Problem Statement

The task is to find the number of continuous subarrays in a given array of integers (nums) that contain exactly k odd numbers. These subarrays are termed as "nice" subarrays. The input to the function will be the array nums and the integer k. The output should be an integer representing how many such "nice" subarrays exist.

Examples

Example 1

Input:

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

Output:

2

Explanation:

The only sub-arrays with 3 odd numbers are [1,1,2,1] and [1,2,1,1].

Example 2

Input:

nums = [2,4,6], k = 1

Output:

0

Explanation:

There are no odd numbers in the array.

Example 3

Input:

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

Output:

16

Constraints

  • 1 <= nums.length <= 50000
  • 1 <= nums[i] <= 10^5
  • 1 <= k <= nums.length

Approach and Intuition

The problem involves analyzing subarrays for a specific count of odd numbers. Given the constraints and nature of the problem, a brute-force solution could be too slow, especially with large arrays. Here's an approach to solve the problem efficiently:

  1. Transform the Problem:
    Simplify the problem by focusing only on the odd numbers in nums. Convert nums into a binary representation where 1 denotes an odd number and 0 denotes an even number.

  2. Use Prefix Sum and HashMap:

    • The idea is to use a prefix sum to count odd numbers up to each index.
    • Create a hashmap to store how many times each count of odd numbers has been seen as a prefix sum.
    • For each element, calculate the current count of odd numbers using the prefix sum.
    • The key insight is that if at some index i the prefix sum is p, and we have previously seen p-k x times (using the hashmap), then there are x subarrays ending at i which have k odd numbers.
  3. Iterate Through Nums:

    • Initialize the hashmap with {0: 1} to handle the case where a subarray with exactly k odd numbers starts from the beginning.
    • As you iterate through nums, update the prefix sum based on whether the current number is odd.
    • For each updated prefix sum, calculate how many times the (current prefix sum) - k has occurred, as it will give the count of subarrays ending at this position that are "nice".
  4. Count "Nice" Subarrays:

    • For each index, update the count of "nice" subarrays by adding the count found in the previous step.
    • Also, update the hashmap to reflect the current prefix sum count.

Using the data from the examples:

  • For nums = [1,1,2,1,1] and k = 3, convert to [1,1,0,1,1]:
    • The prefix sums would be [1, 2, 2, 3, 4] and you determine counts of reaching each prefix sum considering k.

Considering this method is efficient and direct, it caters well to the constraints provided, specifically handling large arrays up to the length of 50,000.

Solutions

  • C++
  • Java
  • Python
cpp
class Solution {
public:
    int countKSubarrays(vector<int>& nums, int k) {
        return atMostK(nums, k) - atMostK(nums, k - 1);
    }

private:
    int atMostK(vector<int>& nums, int k) {
        int count = 0, result = 0, left = 0;

        for (int right = 0; right < nums.size(); right++) {
            count += nums[right] % 2;

            while (count > k) {
                count -= nums[left] % 2;
                left++;
            }
            result += right - left + 1;
        }

        return result;
    }
};

To efficiently compute the number of "nice" subarrays with k odd numbers in C++, the provided solution implements an approach based on the difference between scenarios when there are at most k odd numbers versus at most k-1 odd numbers.

  • Begin by defining the countKSubarrays function which relies on reusing the logic meant to calculate the count of subarrays with at most k odd numbers by using the helper function atMostK.
  • Implement the atMostK function that will keep track of count, the number of odd numbers, result, the count of valid subarrays, and left, a pointer used for indicating the start of a window.
  • Utilize a sliding window strategy:
    • Incrementally expand the window to include more elements (right pointer), updating the count of odd elements.
    • If the count exceeds k, adjust the left pointer to shrink the window until the count is appropriate again.
    • Update the count of valid subarrays for each position of the right pointer, accumulating results using the expression result += right - left + 1 to consider all subarrays ending at right.

This solution is effective in determining the number of subarrays that exactly contain k odd numbers by leveraging direct subtraction between two conditions, ensuring optimal computation and clearer results through the difference of outcomes for k and k-1. This method is highly efficient, using a sliding window approach for a time complexity of O(n) where n is the number of elements in the input array, providing a significant advantage for large datasets.

java
class Solution {

    public int countOddSubarrays(int[] arr, int k) {
        return countAtMost(arr, k) - countAtMost(arr, k - 1);
    }

    private int countAtMost(int[] arr, int k) {
        int countOdds = 0, result = 0, left = 0;

        for (int right = 0; right < arr.length; right++) {
            countOdds += arr[right] % 2;
            // Adjust the left index so countOdds is at most k
            while (countOdds > k) {
                countOdds -= arr[left] % 2;
                left++;
            }
            // Add the number of valid subarrays ending at right
            result += right - left + 1;
        }

        return result;
    }
}

This Java solution is designed to solve the problem of counting the number of subarrays with exactly k odd numbers. The code utilizes two major functions: countOddSubarrays and countAtMost.

  • Start by analyzing the countOddSubarrays method. It leverages the operation of helper function countAtMost to find subarrays with at most k odd numbers and subarrays with at most k - 1 odd numbers. The difference between these two counts gives the exact number of subarrays with exactly k odd numbers.

  • Dive deeper into the countAtMost method, which is a sliding window technique used to maintain a dynamic scope of subarray indices [left, right]. Here, countOdds keeps track of the number of odd numbers within the current window.

    • Iterate over the array using right as the moving boundary of the window.
    • Update the count of odd numbers countOdds by checking if the current element is odd.
    • If countOdds exceeds k, adjust the left point of the window to reduce the countOdds until it is at most k.
    • For each position of right, increment the result by the number of valid subarrays ending at right, which is quantified by the gap between right and left plus one (i.e., right - left + 1).

This method efficiently uses the sliding window concept, allowing the function to maintain an adaptive list of candidate subarrays while controlling the maximum allowed odd elements, resulting in an optimal calculation of the desired count of nice subarrays.

python
class Solution:
    def countOddSubarrays(self, array: List[int], count: int) -> int:
        return self.subarrayCountLessThanEqual(array, count) - self.subarrayCountLessThanEqual(array, count - 1)

    def subarrayCountLessThanEqual(self, array: List[int], threshold: int) -> int:
        odd_count, result, left = 0, 0, 0
        for right in range(len(array)):
            odd_count += array[right] % 2
            while odd_count > threshold:
                odd_count -= array[left] % 2
                left += 1
            result += right - left + 1
        return result

This Python code defines a method to count the number of subarrays with a given number of odd elements in a list of integers. The solution uses the two-pointer technique to efficiently find the desired subarrays.

  • The countOddSubarrays function calculates the difference between:

    • The number of subarrays with odd counts less than or equal to count
    • The number of subarrays with odd counts less than count

    This difference effectively returns the number of subarrays that have exactly count odd numbers.

  • The helper method subarrayCountLessThanEqual efficiently counts how many subarrays have odd counts less than or equal to a specified threshold threshold. This is accomplished by using two variables, left and right, to maintain a sliding window:

    1. Increment odd_count when an odd element is encountered as the right pointer advances.
    2. If odd_count exceeds the threshold, increment the left pointer to reduce the odd_count.
    3. Add to the result the number of valid subarrays ending at the current right pointer.

This systematic approach ensures optimal counting of the subarrays within the given constraints, using a combination of mathematical computation and efficient looping structures.

Comments

No comments yet.