Editorial
Solution walkthrough
Review the explanation, then compare the reference implementation.
Video explanation
Solution
Intuition
A value appearing f times in a window contributes f*(f - 1)/2 equal-value index pairs. Extending a window cannot remove pairs. Once a start position reaches at least k pairs, every later ending position also forms a good subarray with that start.
Approach
Maintain window frequencies and the total pair count. When adding or removing a value, replace its old pair contribution with its new one. After extending right, while the window has at least k pairs, add n - right for all valid endings of the current left boundary, then remove that leftmost value and advance left. Each start is counted once, at its earliest qualifying end. Return the total.
class Solution:
def countGood(self, nums: List[int], k: int) -> int:
n = len(nums)
seen = defaultdict(int)
res = 0
def nC2(n):
if n < 2:
return 0
return n * (n - 1) // 2
pairs = 0
left = 0
for right in range(n):
pairs -= nC2(seen[nums[right]])
seen[nums[right]] += 1
pairs += nC2(seen[nums[right]])
while pairs >= k:
res += n - right
pairs -= nC2(seen[nums[left]])
seen[nums[left]] -= 1
pairs += nC2(seen[nums[left]])
left += 1
return resComplexity analysis
Let n = nums.length and u be the number of distinct values. Time: O(n), because both sliding-window pointers advance monotonically. Auxiliary space: O(u) for frequencies.
