题意:
给定一个正整数数组 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].
示例 2:
输入:A = [1,2,1,3,4], K = 3 输出:3 解释:恰好由 3 个不同整数组成的子数组:[1,2,1,3], [2,1,3], [1,3,4].
提示:
1 <= A.length <= 20000
1 <= A[i] <= A.length
1 <= K <= A.length
思路:
采用滑动窗口,对于每个A[right],考虑两种情况:
1.一种是 A[right] 是已经出现过的数字,那么只要以A[right-1]为结尾的“好子数组”都肯定满足“好子数组”的条件,这个时候只需要记录以A[right-1]为结尾的“好子数组”的数目,然后加上left向右收缩得到的增量;
2.一种是 A[right] 是新的数字,那么需要将left往右收缩,满足当前滑动窗口内不同数字为K,然后left再尽可能往右缩,得到的增量就是当前情况的“好子数组”个数。
让我们通过一个例子来形象化上面的思路,考虑数组:1 1 2 1 1 2 2 3
我们维护一个pre值,初始化为1
a[2]=2,left向右缩到位置1,pre=2,ans+=pre,此时满足题意的有 1 1 2、1 2
a[3]=1,left向右缩到位置2,pre=3,ans+=pre,此时满足题意的有 1 1 2 1、1 2 1、2 1
a[4]=1,left不用缩,pre=3,ans+=pre,此时满足题意的有 1 1 2 1 1、1 2 1 1、2 1 1
a[5]=2,left向右缩到位置4,pre=5,ans+=pre,此时满足题意的有 1 1 2 1 1 2、1 2 1 1 2、2 1 1 2、1 1 2、1 2
a[6]=2,left不用缩,pre=5,ans+=pre,此时满足题意的有 1 1 2 1 1 2 2、1 2 1 1 2 2、2 1 1 2 2、1 1 2 2、1 2 2
a[7]=3,此时滑动窗口中不同数字大于K,先讲left缩到位置5满足要求,将pre置为1,然后再往右缩到位置6,pre=2,ans+=pre,此时满足题意得有 2 2 3、2 3
综上所述,当left不能缩的时候,就相当于是在之前统计的情况上后面加上当前数字;可以缩,就相当于多了left在向右缩的过程中出现的情况
1 class Solution { 2 public: 3 int num[20010]; 4 int subarraysWithKDistinct(vector<int>& A, int K) { 5 int cnt=0,ans=0,pre=1,l=0,r=0; 6 while(r<A.size()){ 7 num[A[r]]++; 8 if(num[A[r++]]==1)cnt++; 9 if(cnt<K)continue; 10 if(cnt==K){ 11 while(num[A[l]]-1>=1)pre++,num[A[l]]--,l++; 12 ans+=pre; 13 } 14 else { 15 while(num[A[l]]-1>=1)num[A[l]]--,l++; 16 num[A[l]]--; l++; 17 pre=1; cnt--; 18 while(num[A[l]]-1>=1)pre++,num[A[l]]--,l++; 19 ans+=pre; 20 } 21 } 22 return ans; 23 } 24 };