Count Subarrays Where Max Element Appears at Least K Times
Given an integer array numskk
Example 1
Output: 6
Explanation: the subarrays are [1, 3, 2, 3], [1, 3, 2, 3, 3], [3, 2, 3], [3, 2, 3, 3], [2, 3, 3] and [3, 3].
Example 2
Output: 0
Explanation: 4 appears only once.
How to Think About It
Step 1: Only one value matters
Find maxkmax
Step 2: Count by the right end
Fix the right end of a subarray at rightmax
Step 3: Find where that block ends
Keep a window [left, right]maxnums[right]kleftk - 1leftkleftright
Step 4: Use a long
The count can reach about n² / 2, which for n = 105 is far beyond an int
Walkthrough
nums = [1, 3, 2, 3, 3]k = 2max = 3
| right (value) | left after shrinking | Copies of 3 in window | Subarrays added | Total |
|---|---|---|---|---|
| 0 (1) | 0 | 0 | 0 | 0 |
| 1 (3) | 0 | 1 | 0 | 0 |
| 2 (2) | 0 | 1 | 0 | 0 |
| 3 (3) | 2 | 1 | 2 (starts 0 and 1) | 2 |
| 4 (3) | 4 | 1 | 4 (starts 0 to 3) | 6 |
Java Solution
result += left
public class CountSubarraysWhereMaxAppearsKTimes {
public static long countSubarrays(int[] nums, int k) {
int max = 0;
for (int x : nums) {
max = Math.max(max, x);
}
long result = 0;
int left = 0;
int count = 0; // copies of max in nums[left..right]
for (int right = 0; right < nums.length; right++) {
if (nums[right] == max) {
count++;
}
while (count == k) { // shrink until the window has k - 1 copies
if (nums[left] == max) {
count--;
}
left++;
}
result += left; // starts 0 .. left-1 all give >= k copies
}
return result;
}
public static void main(String[] args) {
System.out.println(countSubarrays(new int[] {1, 3, 2, 3, 3}, 2)); // 6
System.out.println(countSubarrays(new int[] {1, 4, 2, 1}, 3)); // 0
}
}
Complexity
- Time: O(n): one pass to find the maximum, one pass for the window.
- Space: O(1).
The same "count all starts before left" step is used in