【题解】力扣992. K 个不同整数的子数组
题目来源
题目描述:给定一个正整数数组 A
,如果 A
的某个子数组中不同整数的个数恰好为 K
,则称 A
的这个连续、不一定独立的子数组为好子数组。
思路
恰好包含K种不同整数的子区间 = 最多包含K种整数的子区间 - 最多包含K-1种整数的子区间
利用滑动窗口求最多包含K种整数的子区间
例:求A中由K个不同整数组成的最长子数组的长度
private static int atMostK(int[] A, int K){
int len = A.length;
int[] freq = new int[len];
int left = 0, right = 0;
int cnt = 0;
int res = 0;
while(right < len){
if(freq[A[right]] == 0){
cnt++;
}
freq[A[right]]++;
while(cnt < K){
freq[A[left]]--;
if(freq[A[left]] == 0){
cnt--;
}
left++;
}
res = Math.max(res, right-left+1);
right++;
}
return res;
}
举例而言:对于 A = [1,2,1,2,3], K = 2
,我们运行上面的代码会寻找到最长子数组 [1, 2, 1, 2]
的长度为 4.
上面求的是A中由K个不同整数组成的最长子数组的长度,如果问A中最多K个不同整数组成的子数组的个数,该怎么办?
答:只需要把res = Math.max(res, right-left+1)
改成res += right-left+1
即可。right-left+1
为区间长度。
例:对于A=[1,2,1,2,3], K=2
。会得到满足题意的子数组[1,2,1,2]
和[2,3]
。
- 对于子数组
[1,2,1,2]
,它的所有子数组,满足题意的,共有1+2+3+4=10个数组- 以第一个 1 为右端点的满足题意的子数组为
[1]
; - 以第一个 2 为右端点的满足题意的子数组为
[1,2]
,[2]
; - 以第二个 1 为右端点的满足题意的子数组为
[1,2,1]
,[2,1]
,[1]
; - 以第二个 2 为右端点的满足题意的子数组为
[1,2,1,2]
,[2,1,2]
,[1,2]
,[2]
;
- 以第一个 1 为右端点的满足题意的子数组为
- 对于子数组
[2,3]
,它的所有子数组都满足题意,共有3个子数组。- 以
2
为右端点的满足题意的子数组,在上面已经统计过了,因此不要重复统计。 - 以
3
为右端点的满足题意的子数组为[2, 3], [3]
。
- 以
所以总的数组 A 有 12 个由 最多 2 个不同整数组成的子数组。
所以,当 right
到达一个新位置之后,把 left
调整到满足题意的位置,当前[left, right]
区间内符合条件的并且以 right
为右端点的子数组个数 为 right - left + 1
。当 right
指针把数组的每个位置遍历一遍,就得到了以每个位置作为区间右短点的子数组长度,累加得到的就是结果。
这个思想有点类似于动态规划,如果 dp[i]
表示以 i
为右端点的符合题意的子数组个数,那么sum(dp[0..N-1])
就能求得所有子数组的个数之和。
代码
class Solution {
public int subarraysWithKDistinct(int[] A, int K) {
return mostKSubarrays(A, K) - mostKSubarrays(A, K-1);
}
private static int mostKSubarrays(int[] a, int k) {
int len = a.length;
int[] freq = new int[len+1]; // 记录数字出现的频次
int left = 0,right = 0;
int cnt = 0; // 记录不同数组的个数
int res = 0; // 返回结果
while(right < len){
if(freq[a[right]] == 0){
cnt++;
}
freq[a[right]]++; // 频次增加
while(cnt > k){ // 不同数字超过K,即不符合题意
freq[a[left]]--; // 不能与下面的left++顺序写反
if(freq[a[left]] == 0){
cnt--;
}
left++;
}
res += right - left + 1; // 累加结果
right++; // 指针右移
}
return res;
}
}
复杂度分析:
- 时间复杂度:
O(n)
- 空间复杂度:
O(n)