Add Count Nice Subarrays sliding using window algorithm (#7206)

* Add Count Nice Subarrays sliding window algorithm

* Add detailed comments and reference to CountNiceSubarrays

* Fix clang-format issues in CountNiceSubarrays

* Added extra edge cases

* changes made
This commit is contained in:
Tarunj Gupta
2026-01-10 21:02:19 +05:30
committed by GitHub
parent fe6066b332
commit 1644db2a34
2 changed files with 154 additions and 0 deletions

View File

@@ -0,0 +1,99 @@
package com.thealgorithms.slidingwindow;
/**
* Counts the number of "nice subarrays".
* A nice subarray is a contiguous subarray that contains exactly k odd numbers.
*
* This implementation uses the sliding window technique.
*
* Reference:
* https://leetcode.com/problems/count-number-of-nice-subarrays/
*
* Time Complexity: O(n)
* Space Complexity: O(n)
*/
public final class CountNiceSubarrays {
// Private constructor to prevent instantiation
private CountNiceSubarrays() {
}
/**
* Returns the count of subarrays containing exactly k odd numbers.
*
* @param nums input array of integers
* @param k number of odd elements required in the subarray
* @return number of nice subarrays
*/
public static int countNiceSubarrays(int[] nums, int k) {
int n = nums.length;
// Left pointer of the sliding window
int left = 0;
// Tracks number of odd elements in the current window
int oddCount = 0;
// Final answer: total number of nice subarrays
int result = 0;
/*
* memo[i] stores how many valid starting positions exist
* when the left pointer is at index i.
*
* This avoids recomputing the same values again.
*/
int[] memo = new int[n];
// Right pointer moves forward to expand the window
for (int right = 0; right < n; right++) {
// If current element is odd, increment odd count
if ((nums[right] & 1) == 1) {
oddCount++;
}
/*
* If oddCount exceeds k, shrink the window from the left
* until oddCount becomes valid again.
*/
if (oddCount > k) {
left += memo[left];
oddCount--;
}
/*
* When the window contains exactly k odd numbers,
* count all possible valid subarrays starting at `left`.
*/
if (oddCount == k) {
/*
* If this left index hasn't been processed before,
* count how many consecutive even numbers follow it.
*/
if (memo[left] == 0) {
int count = 0;
int temp = left;
// Count consecutive even numbers
while ((nums[temp] & 1) == 0) {
count++;
temp++;
}
/*
* Number of valid subarrays starting at `left`
* is (count of even numbers + 1)
*/
memo[left] = count + 1;
}
// Add number of valid subarrays for this left position
result += memo[left];
}
}
return result;
}
}

View File

@@ -0,0 +1,55 @@
package com.thealgorithms.slidingwindow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
public class CountNiceSubarraysTest {
@Test
void testExampleCase() {
int[] nums = {1, 1, 2, 1, 1};
assertEquals(2, CountNiceSubarrays.countNiceSubarrays(nums, 3));
}
@Test
void testAllEvenNumbers() {
int[] nums = {2, 4, 6, 8};
assertEquals(0, CountNiceSubarrays.countNiceSubarrays(nums, 1));
}
@Test
void testSingleOdd() {
int[] nums = {1};
assertEquals(1, CountNiceSubarrays.countNiceSubarrays(nums, 1));
}
@Test
void testMultipleChoices() {
int[] nums = {2, 2, 1, 2, 2, 1, 2};
assertEquals(6, CountNiceSubarrays.countNiceSubarrays(nums, 2));
}
@Test
void testTrailingEvenNumbers() {
int[] nums = {1, 2, 2, 2};
assertEquals(4, CountNiceSubarrays.countNiceSubarrays(nums, 1));
}
@Test
void testMultipleWindowShrinks() {
int[] nums = {1, 1, 1, 1};
assertEquals(3, CountNiceSubarrays.countNiceSubarrays(nums, 2));
}
@Test
void testEvensBetweenOdds() {
int[] nums = {2, 1, 2, 1, 2};
assertEquals(4, CountNiceSubarrays.countNiceSubarrays(nums, 2));
}
@Test
void testShrinkWithTrailingEvens() {
int[] nums = {2, 2, 1, 2, 2, 1, 2, 2};
assertEquals(9, CountNiceSubarrays.countNiceSubarrays(nums, 2));
}
}