From 9fb75ce2d166427bee458efa471ebd5e6afebeaa Mon Sep 17 00:00:00 2001 From: tarunjgupta Date: Sat, 10 Jan 2026 15:34:39 +0530 Subject: [PATCH 1/5] Add Count Nice Subarrays sliding window algorithm --- .../slidingwindow/CountNiceSubarrays.java | 39 +++++++++++++++++++ .../slidingwindow/CountNiceSubarraysTest.java | 29 ++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 src/main/java/com/thealgorithms/slidingwindow/CountNiceSubarrays.java create mode 100644 src/test/java/com/thealgorithms/slidingwindow/CountNiceSubarraysTest.java diff --git a/src/main/java/com/thealgorithms/slidingwindow/CountNiceSubarrays.java b/src/main/java/com/thealgorithms/slidingwindow/CountNiceSubarrays.java new file mode 100644 index 000000000000..21c680f9373d --- /dev/null +++ b/src/main/java/com/thealgorithms/slidingwindow/CountNiceSubarrays.java @@ -0,0 +1,39 @@ +package com.thealgorithms.slidingwindow; + +public class CountNiceSubarrays { + private CountNiceSubarrays() { + } + + public static int countNiceSubarrays(int[] nums, int k) { + int n = nums.length; + int left = 0; + int oddCount = 0; + int result = 0; + int[] memo = new int[n]; + + for (int right = 0; right < n; right++) { + if ((nums[right] & 1) == 1) { + oddCount++; + } + + if (oddCount > k) { + left += memo[left]; + oddCount--; + } + + if (oddCount == k) { + if (memo[left] == 0) { + int count = 0; + int temp = left; + while ((nums[temp] & 1) == 0) { + count++; + temp++; + } + memo[left] = count + 1; + } + result += memo[left]; + } + } + return result; + } +} diff --git a/src/test/java/com/thealgorithms/slidingwindow/CountNiceSubarraysTest.java b/src/test/java/com/thealgorithms/slidingwindow/CountNiceSubarraysTest.java new file mode 100644 index 000000000000..1a1fc05c6514 --- /dev/null +++ b/src/test/java/com/thealgorithms/slidingwindow/CountNiceSubarraysTest.java @@ -0,0 +1,29 @@ +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(9, CountNiceSubarrays.countNiceSubarrays(nums, 2)); + } +} From b68d8bd885b8a30690c97d13c8bb339083f557b9 Mon Sep 17 00:00:00 2001 From: tarunjgupta Date: Sat, 10 Jan 2026 16:04:53 +0530 Subject: [PATCH 2/5] Add detailed comments and reference to CountNiceSubarrays --- .../slidingwindow/CountNiceSubarrays.java | 62 ++++++++++++++++++- .../slidingwindow/CountNiceSubarraysTest.java | 2 +- 2 files changed, 62 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/thealgorithms/slidingwindow/CountNiceSubarrays.java b/src/main/java/com/thealgorithms/slidingwindow/CountNiceSubarrays.java index 21c680f9373d..46f8deeb58dd 100644 --- a/src/main/java/com/thealgorithms/slidingwindow/CountNiceSubarrays.java +++ b/src/main/java/com/thealgorithms/slidingwindow/CountNiceSubarrays.java @@ -1,36 +1,96 @@ package com.thealgorithms.slidingwindow; -public class CountNiceSubarrays { +/** + * 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]; } } diff --git a/src/test/java/com/thealgorithms/slidingwindow/CountNiceSubarraysTest.java b/src/test/java/com/thealgorithms/slidingwindow/CountNiceSubarraysTest.java index 1a1fc05c6514..d83974c0f48a 100644 --- a/src/test/java/com/thealgorithms/slidingwindow/CountNiceSubarraysTest.java +++ b/src/test/java/com/thealgorithms/slidingwindow/CountNiceSubarraysTest.java @@ -24,6 +24,6 @@ void testSingleOdd() { @Test void testMultipleChoices() { int[] nums = {2, 2, 1, 2, 2, 1, 2}; - assertEquals(9, CountNiceSubarrays.countNiceSubarrays(nums, 2)); + assertEquals(6, CountNiceSubarrays.countNiceSubarrays(nums, 2)); } } From 8ea4494d0b4c9acaae594e9147fc0209e0147b58 Mon Sep 17 00:00:00 2001 From: tarunjgupta Date: Sat, 10 Jan 2026 16:16:51 +0530 Subject: [PATCH 3/5] Fix clang-format issues in CountNiceSubarrays --- .../com/thealgorithms/slidingwindow/CountNiceSubarraysTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/test/java/com/thealgorithms/slidingwindow/CountNiceSubarraysTest.java b/src/test/java/com/thealgorithms/slidingwindow/CountNiceSubarraysTest.java index d83974c0f48a..a0d8dbc7cb82 100644 --- a/src/test/java/com/thealgorithms/slidingwindow/CountNiceSubarraysTest.java +++ b/src/test/java/com/thealgorithms/slidingwindow/CountNiceSubarraysTest.java @@ -1,5 +1,7 @@ package com.thealgorithms.slidingwindow; + import static org.junit.jupiter.api.Assertions.assertEquals; + import org.junit.jupiter.api.Test; public class CountNiceSubarraysTest { From fc95e6b7ab8803fa880f2a453880cc6e9358eaad Mon Sep 17 00:00:00 2001 From: tarunjgupta Date: Sat, 10 Jan 2026 20:32:37 +0530 Subject: [PATCH 4/5] Added extra edge cases --- .../slidingwindow/CountNiceSubarraysTest.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/test/java/com/thealgorithms/slidingwindow/CountNiceSubarraysTest.java b/src/test/java/com/thealgorithms/slidingwindow/CountNiceSubarraysTest.java index a0d8dbc7cb82..464de77511f6 100644 --- a/src/test/java/com/thealgorithms/slidingwindow/CountNiceSubarraysTest.java +++ b/src/test/java/com/thealgorithms/slidingwindow/CountNiceSubarraysTest.java @@ -28,4 +28,29 @@ 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)); + } + } From 102ae33cc76a595ee89c0d53f59bd6f75f8672cd Mon Sep 17 00:00:00 2001 From: tarunjgupta Date: Sat, 10 Jan 2026 20:38:25 +0530 Subject: [PATCH 5/5] changes made --- .../slidingwindow/CountNiceSubarraysTest.java | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/test/java/com/thealgorithms/slidingwindow/CountNiceSubarraysTest.java b/src/test/java/com/thealgorithms/slidingwindow/CountNiceSubarraysTest.java index 464de77511f6..71bf24cc9e30 100644 --- a/src/test/java/com/thealgorithms/slidingwindow/CountNiceSubarraysTest.java +++ b/src/test/java/com/thealgorithms/slidingwindow/CountNiceSubarraysTest.java @@ -31,20 +31,20 @@ void testMultipleChoices() { @Test void testTrailingEvenNumbers() { - int[] nums = {1, 2, 2, 2}; - assertEquals(4, CountNiceSubarrays.countNiceSubarrays(nums, 1)); + 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)); + 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)); + int[] nums = {2, 1, 2, 1, 2}; + assertEquals(4, CountNiceSubarrays.countNiceSubarrays(nums, 2)); } @Test @@ -52,5 +52,4 @@ void testShrinkWithTrailingEvens() { int[] nums = {2, 2, 1, 2, 2, 1, 2, 2}; assertEquals(9, CountNiceSubarrays.countNiceSubarrays(nums, 2)); } - }