Leetcode 2537. Count the Number of Good Subarrays
Table of Contents
Problem Informations
- Problem Index: 2537
- Problem Link: Count the Number of Good Subarrays
- Topics: Array, Hash Table, Sliding Window
Problem Description
Given an integer array nums
and an integer k
, return the number of good subarrays of nums
.
A subarray arr
is good if there are at least k
pairs of indices (i, j)
such that $i < j$ and $arr[i] == arr[j]$.
A subarray is a contiguous non-empty sequence of elements within an array.
Example 1:
Input: nums = [1,1,1,1,1], k = 10
Output: 1
Explanation: The only good subarray is the array nums itself.
Example 2:
Input: nums = [3,1,4,3,2,2,4], k = 2
Output: 4
Explanation: There are 4 different good subarrays:
- [3,1,4,3,2,2] that has 2 pairs.
- [3,1,4,3,2,2,4] that has 3 pairs.
- [1,4,3,2,2,4] that has 2 pairs.
- [4,3,2,2,4] that has 2 pairs.
Constraints:
- $1 \leq nums.length \leq 10^5$
- $1 \leq nums[i], k \leq 10^9$
Intuition
The problem requires us to determine the number of contiguous subarrays for which there are at least k
pairs of indices (i, j)
such that i < j
and arr[i] == arr[j]
. This implies that we need to find subarrays with a certain level of repetition. The focus is to efficiently track the number of such pairs within subarrays in order to ascertain when a subarray becomes “good”. We recognize that as the length of the subarray increases, the number of pairs can only increase or stay the same due to more elements potentially repeating.
Approach
We employ a two-pointer or sliding window technique combined with a frequency hashmap to track occurrences of elements and efficiently count pairs within the current window.
Initialize Required Variables:
ans
, to store the total count of good subarrays, is initialized to zero.currentPairs
, to record the number of pairs within the current window, is initialized to zero.frequency
, an unordered hashmap, maps each element to its frequency in the current window.left
, the starting index of the window, is initialized to 0.
Expand the Window:
- Traverse the array using
right
as the endpoint of the current window. - For each element
nums[right]
, updatecurrentPairs
by adding the frequency ofnums[right]
from the hashmap. This is because each occurrence ofnums[right]
creates additional pairs with all its previous occurrences within the window. - Increment the frequency of
nums[right]
in the hashmap.
- Traverse the array using
Check and Contract the Window:
- While the number of pairs
currentPairs
is greater than or equal tok
and theleft
pointer is less than or equal toright
, execute the inner loop:- Every subarray that starts from
left
and ends anywhere fromright
ton-1
is good because they satisfy the pair requirement. - Therefore, increment
ans
by(n - right)
which represents all such valid subarrays. - To explore other potential good subarrays, reduce the window size by moving
left
to the right:- Decrement the frequency of
nums[left]
in the hashmap. - Reduce
currentPairs
by the new frequency ofnums[left]
, since removing an element affects the pairing count. - Increment
left
to incrementally reduce the window size.
- Decrement the frequency of
- Every subarray that starts from
- While the number of pairs
Return the Result:
- After the loop completes,
ans
contains the total number of good subarrays that satisfy the condition throughout the entire array.
- After the loop completes,
This approach efficiently traverses the nums
array once, making pair counts and subarray evaluations with an overall linear complexity relative to the size of the array. This ensures performance is optimal even with larger input sizes up to the constraint limits.
Code
C++
class Solution {
public:
long long countGood(vector<int>& nums, int k) {
long long ans = 0;
long long currentPairs = 0;
unordered_map<int, long long> frequency;
int left = 0;
int n = nums.size();
for (int right = 0; right < n; ++right) {
// Each time we add nums[right], it forms new pairs with its previous occurrences.
currentPairs += frequency[nums[right]];
frequency[nums[right]]++;
// If current window [left, right] contains at least k pairs,
// every subarray starting at left and ending from right to n-1 will be "good".
while (currentPairs >= k && left <= right) {
// All subarrays starting from `left` to `right` with this `right` are valid.
ans += (n - right);
// Remove nums[left] from the current window, reducing pair count.
frequency[nums[left]]--;
currentPairs -= frequency[nums[left]];
++left;
}
}
return ans;
}
};
Python
class Solution:
def countGood(self, nums, k):
ans = 0
currentPairs = 0
frequency = {}
left = 0
n = len(nums)
for right in range(n):
# Each time we add nums[right], it forms new pairs with its previous occurrences.
currentPairs += frequency.get(nums[right], 0)
frequency[nums[right]] = frequency.get(nums[right], 0) + 1
# If current window [left, right] contains at least k pairs,
# every subarray starting at left and ending from right to n-1 will be "good".
while currentPairs >= k and left <= right:
# All subarrays starting from `left` to `right` with this `right` are valid.
ans += (n - right)
# Remove nums[left] from the current window, reducing pair count.
frequency[nums[left]] -= 1
currentPairs -= frequency[nums[left]]
left += 1
return ans
Complexity
Time complexity: $O(n)$
The time complexity is $O(n)$ because we are using a two-pointer technique, or sliding window approach, which involves iterating through thenums
array with bothright
andleft
pointers. For eachright
pointer position, theleft
pointer only moves forward, ensuring that each element innums
is processed a constant number of times.Specifically, the outer for-loop iterates through the array with the
right
pointer, and within this loop, theleft
pointer controls the window size to ensure the number of good pairs is checked efficiently. The inner while-loop iterates without resetting theleft
pointer backward, therefore maintaining a linear traversal of elements, ensuring an overall time complexity of $O(n)$.Space complexity: $O(n)$
The space complexity is $O(n)$ because we utilize an unordered map (frequency
) to store the count of each element within the current window. In the worst-case scenario, all elements innums
are distinct, resulting in the map storingn
elements. Hence, the required space grows linearly with respect to the input size.
Disclaimer: All reference materials on this website are sourced from the internet and are intended for learning purposes only. If you believe any content infringes upon your rights, please contact me at csnote.cc@gmail.com, and I will remove the relevant content promptly.
Feedback Welcome: If you notice any errors or areas for improvement in the articles, I warmly welcome your feedback and corrections. Your input will help this blog provide better learning resources. This is an ongoing process of learning and improvement, and your suggestions are valuable to me. You can reach me at csnote.cc@gmail.com.