Skip to content

Commit 1644db2

Browse files
authored
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
1 parent fe6066b commit 1644db2

File tree

2 files changed

+154
-0
lines changed

2 files changed

+154
-0
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package com.thealgorithms.slidingwindow;
2+
3+
/**
4+
* Counts the number of "nice subarrays".
5+
* A nice subarray is a contiguous subarray that contains exactly k odd numbers.
6+
*
7+
* This implementation uses the sliding window technique.
8+
*
9+
* Reference:
10+
* https://leetcode.com/problems/count-number-of-nice-subarrays/
11+
*
12+
* Time Complexity: O(n)
13+
* Space Complexity: O(n)
14+
*/
15+
public final class CountNiceSubarrays {
16+
17+
// Private constructor to prevent instantiation
18+
private CountNiceSubarrays() {
19+
}
20+
21+
/**
22+
* Returns the count of subarrays containing exactly k odd numbers.
23+
*
24+
* @param nums input array of integers
25+
* @param k number of odd elements required in the subarray
26+
* @return number of nice subarrays
27+
*/
28+
public static int countNiceSubarrays(int[] nums, int k) {
29+
30+
int n = nums.length;
31+
32+
// Left pointer of the sliding window
33+
int left = 0;
34+
35+
// Tracks number of odd elements in the current window
36+
int oddCount = 0;
37+
38+
// Final answer: total number of nice subarrays
39+
int result = 0;
40+
41+
/*
42+
* memo[i] stores how many valid starting positions exist
43+
* when the left pointer is at index i.
44+
*
45+
* This avoids recomputing the same values again.
46+
*/
47+
int[] memo = new int[n];
48+
49+
// Right pointer moves forward to expand the window
50+
for (int right = 0; right < n; right++) {
51+
52+
// If current element is odd, increment odd count
53+
if ((nums[right] & 1) == 1) {
54+
oddCount++;
55+
}
56+
57+
/*
58+
* If oddCount exceeds k, shrink the window from the left
59+
* until oddCount becomes valid again.
60+
*/
61+
if (oddCount > k) {
62+
left += memo[left];
63+
oddCount--;
64+
}
65+
66+
/*
67+
* When the window contains exactly k odd numbers,
68+
* count all possible valid subarrays starting at `left`.
69+
*/
70+
if (oddCount == k) {
71+
72+
/*
73+
* If this left index hasn't been processed before,
74+
* count how many consecutive even numbers follow it.
75+
*/
76+
if (memo[left] == 0) {
77+
int count = 0;
78+
int temp = left;
79+
80+
// Count consecutive even numbers
81+
while ((nums[temp] & 1) == 0) {
82+
count++;
83+
temp++;
84+
}
85+
86+
/*
87+
* Number of valid subarrays starting at `left`
88+
* is (count of even numbers + 1)
89+
*/
90+
memo[left] = count + 1;
91+
}
92+
93+
// Add number of valid subarrays for this left position
94+
result += memo[left];
95+
}
96+
}
97+
return result;
98+
}
99+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.thealgorithms.slidingwindow;
2+
3+
import static org.junit.jupiter.api.Assertions.assertEquals;
4+
5+
import org.junit.jupiter.api.Test;
6+
7+
public class CountNiceSubarraysTest {
8+
@Test
9+
void testExampleCase() {
10+
int[] nums = {1, 1, 2, 1, 1};
11+
assertEquals(2, CountNiceSubarrays.countNiceSubarrays(nums, 3));
12+
}
13+
14+
@Test
15+
void testAllEvenNumbers() {
16+
int[] nums = {2, 4, 6, 8};
17+
assertEquals(0, CountNiceSubarrays.countNiceSubarrays(nums, 1));
18+
}
19+
20+
@Test
21+
void testSingleOdd() {
22+
int[] nums = {1};
23+
assertEquals(1, CountNiceSubarrays.countNiceSubarrays(nums, 1));
24+
}
25+
26+
@Test
27+
void testMultipleChoices() {
28+
int[] nums = {2, 2, 1, 2, 2, 1, 2};
29+
assertEquals(6, CountNiceSubarrays.countNiceSubarrays(nums, 2));
30+
}
31+
32+
@Test
33+
void testTrailingEvenNumbers() {
34+
int[] nums = {1, 2, 2, 2};
35+
assertEquals(4, CountNiceSubarrays.countNiceSubarrays(nums, 1));
36+
}
37+
38+
@Test
39+
void testMultipleWindowShrinks() {
40+
int[] nums = {1, 1, 1, 1};
41+
assertEquals(3, CountNiceSubarrays.countNiceSubarrays(nums, 2));
42+
}
43+
44+
@Test
45+
void testEvensBetweenOdds() {
46+
int[] nums = {2, 1, 2, 1, 2};
47+
assertEquals(4, CountNiceSubarrays.countNiceSubarrays(nums, 2));
48+
}
49+
50+
@Test
51+
void testShrinkWithTrailingEvens() {
52+
int[] nums = {2, 2, 1, 2, 2, 1, 2, 2};
53+
assertEquals(9, CountNiceSubarrays.countNiceSubarrays(nums, 2));
54+
}
55+
}

0 commit comments

Comments
 (0)