滑动窗口系列-Leetcode 992. K 个不同整数的子数组

问题描述

给定一个正整数数组 A,如果 A 的某个子数组中不同整数的个数恰好为 K,则称 A 的这个连续、不一定独立的子数组为好子数组。

(例如,[1,2,3,1,2] 中有 3 个不同的整数:1,2,以及 3。)

返回 A 中好子数组的数目。

示例 1:

输入:A = [1,2,1,2,3], K = 2
输出:7
解释:恰好由 2 个不同整数组成的子数组:[1,2], [2,1], [1,2], [2,3], [1,2,1], [2,1,2], [1,2,1,2].

解题报告

考虑累加以每个数字结尾的好子数组的个数。
那么如何计算以每个数字结尾的子数组的个数呢?
假设 [r,i] 是以 A[i] 结尾的好数组的最小区间,[l,i] 是以 A[i] 结尾的好数组的最大区间,
则每个累加 r-l+1 即可。
所以现在问题变成了 如何计算 lr
l 意味着 [l,i] 的区间中不同整数的个数取不到 K+1 时,不开始更新 l
r 意味着 [r,i] 的区间中不同整数的个数刚取到 K 时,开始更新 r

想法其实挺简单的,但是编码实现时,总是不知如何下手,哎,还是要多多练习吧

这题和 Leetcode 1248. 统计「优美子数组」 的【滑动窗口解法】有着异曲同工之妙,只是 Leetcode 1248 中,数组中只有两类数,奇数&偶数,所以我们不需要令设两个数组来记录窗口内的奇数和偶数。

实现代码

代码部分完全源自参考的文献,侵权必删

class Solution{
    public:
        int subarraysWithKDistinct(vector<int>&A, int K){
            int n=A.size();
            vector<int>cl(n+1, 0), cr(n+1, 0);
            int l=0, r=0, ans=0, nl=0, nr=0;
            for(int i=0;i<n;i++){
                if(cl[A[i]]++==0) nl++;
                while(nl>K){
                    if(--cl[A[l++]]==0) nl--;
                }
                if(cr[A[i]]++==0) nr++;
                while(nr>=K){
                    if(--cr[A[r++]]==0) nr--;
                }

                ans+=(r-l);
            }
            return ans;
        }
};

参考资料

[1] Leetcode 992. K 个不同整数的子数组
[2] 每日算法系列【LeetCode 992】K个不同整数的子数组
[3] Leetcode 1248. 统计「优美子数组」
[4] Leetcode 1248. 统计「优美子数组」【记录奇数位置&滑动窗口&前缀和】

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章