题目描述
https://leetcode-cn.com/problems/subarrays-with-k-different-integers/
思路
- 用哈希表统计两个指针中间,每个数字出现的次数
- 统计出现的数字种类数,sum。当大于K的时候,
从后向前依次处理
,注意保护原有数据
- 防止两个指针中只有K种数据,在循环后再处理一次
为什么是从后向前查找呢?
因为从前向后容易遗漏数据,如果判断条件为sum > K
那么就会忽略掉前面的数据,[1,2], [2,1], [1,2],[1,2,1], [2,1,2]
而如果判断条件为sum >= K
,那么从前向后也是会忽略掉一些数据的,因为我们不能判断后面是否还会出现前面的数据。
所以就采用从后向前遍历的方式,这样可以避免遗漏的情况,sum > K
时再从后向前遍历两个指针,直到数据不满足sum > K
或者 le < ri
为止。
只是在最后需要注意一种情况,就是 两个指针中的数据是sum == K
的情况,那么这些是没有在我们第一次循环中找到的,所以在结尾判断一下这种情况就可以了。
程序代码
class Solution {
public:
int ans = 0;
int subarraysWithKDistinct(vector<int>& A, int K) {
int n = A.size();
vector<int> hash(n+1,0);
int le = 0;
int sum = 0;
for(int i = 0; i < n; i++)
{
if(hash[A[i]] == 0) sum++;
hash[A[i]]++;
while(sum > K && le < i)
{
//从i -> le 搜索
dfs(hash,A,K,le,i,sum);
hash[A[le]]--;
if(hash[A[le]] == 0) sum--;
le++;
}
}
while(sum == K && le < n)
{
dfs(hash,A,K,le,n-1,sum);
hash[A[le]]--;
if(hash[A[le]] == 0) sum--;
le++;
}
return ans;
}
void dfs(vector<int>& hash,vector<int>& A,int K,int le,int ri,int& sum)
{
if(sum < K || le > ri) return;
if(sum == K) ans++;
hash[A[ri]]--;
if(hash[A[ri]] == 0) sum--;
dfs(hash,A,K,le,ri-1,sum);
if(hash[A[ri]] == 0) sum++;
hash[A[ri]]++;
}
};
两个滑动窗口
class Solution {
public:
int subarraysWithKDistinct(vector<int>& A, int K) {
int n = A.size();
vector<int> fLe(n + 1,0), fRi(n + 1, 0);
int l1 = 0, l2 = 0, c1 = 0, c2 = 0;
int res = 0;
for(int i = 0; i < n; i++) {
if(fLe[A[i]] ++ == 0) c1 ++;
if(fRi[A[i]] ++ == 0) c2 ++;
if(c1 < K) continue;
while(c1 > K && l1 <= i)
if(-- fLe[A[l1 ++]] == 0) c1 --;
while(c2 >= K && l2 <= i)
if(-- fRi[A[l2 ++]] == 0) c2 --;
res += l2 - l1;
}
return res;
}
};