Leetcode-2537. 统计好子数组的数目
Problem: 2537. 统计好子数组的数目
思路
滑动窗口
解题过程
思路:
使用滑动窗口来维护子数组,并通过组合计数动态调整满足条件的数对数目。具体来说,我们维护一个窗口[l,r],使得窗口内相同元素的对数至少为 k,并计算这样的窗口数目。
关键观察:
- 当一个元素的频次从 c 增加到 c+1 时,新增加的数对数目为 c(因为新元素可以与之前的 c 个元素形成 c 对)。
- 当一个元素的频次从 c 减少到 c-1 时,减少的数对数目为 c-1(因为移除的元素与剩余的 c-1 个元素的数对被移除)。
算法步骤:
- 使用两个指针 l 和 r 维护滑动窗口,使用哈希表 cnt 记录元素频次,使用变量 t 记录窗口内的数对数目。
- 右指针 r 不断扩展窗口,更新元素频次和数对数目 t。
- 当 t >= k 时,尝试移动左指针 l 缩小窗口,同时更新数对数目 t,直到窗口不再满足条件。
- 此时,以 r 结尾且满足条件的子数组数目为 l(即左端点可以是 0 到 l-1 的任意位置)。
Code
python
class Solution:def countGood(self, nums: List[int], k: int) -> int:n = len(nums)ans = 0l = 0cnt = defaultdict(int) # 记录数组中的元素频次t = 0 # 记录此时窗口的满足i<j且nums[i]=nums[j]的对数for r, x in enumerate(nums):cnt[x] += 1if cnt[x] >= 2:t += cnt[x] - 1while t >= k and l < r:cnt[nums[l]] -= 1if cnt[nums[l]] >= 1:t -= cnt[nums[l]]l += 1ans += lreturn ans
c++
class Solution {
public:long long countGood(vector<int>& nums, int k) {int n = nums.size();long long ans = 0;int l = 0;unordered_map<int, int> cnt;int t = 0;for (int r = 0; r < n; r++) {cnt[nums[r]]++;if (cnt[nums[r]] >= 2)t += cnt[nums[r]] - 1;while (t >= k && l < r) {cnt[nums[l]]--;if (cnt[nums[l]] >= 1)t -= cnt[nums[l]];l++;}ans += l;}return ans;}
};
复杂度
- 时间复杂度: O(n)
- 空间复杂度: O(n),用哈希表存储元素频次。