Given an array A
of positive integers, call a (contiguous, not necessarily distinct) subarray of A
good if the number of different integers in that subarray is exactly K
.
(For example, [1,2,3,1,2]
has 3
different integers: 1
, 2
, and 3
.)
Return the number of good subarrays of A
.
Example 1:
Input: A = [1,2,1,2,3], K = 2
Output: 7
Explanation: Subarrays formed with exactly 2 different integers: [1,2], [2,1], [1,2], [2,3], [1,2,1], [2,1,2], [1,2,1,2].
Example 2:
Input: A = [1,2,1,3,4], K = 3
Output: 3
Explanation: Subarrays formed with exactly 3 different integers: [1,2,1,3], [2,1,3], [1,3,4].
Note:
1 <= A.length <= 20000
1 <= A[i] <= A.length
1 <= K <= A.length
K个不同整数的子数组。
题意是给定一个正整数数组 A,如果 A 的某个子数组中不同整数的个数恰好为 K,则称 A 的这个连续、不一定独立的子数组为好子数组。返回A中好子数组的数量。
思路依然是滑动窗口,但是这一题是没法直接套用76题的模板的,有一些变动(引用)。回忆前面做的滑动窗口的题目,有求过子数组里面最多K个不同元素的题(340),所以这个解法的思路是求子数组里面最多K个不同元素的子数组的数量 - 子数组里面最多K - 1个不同元素的子数组的数量。之前能用76题的模板解决的题,一般都是在某一个范围内最多或者最少有几个符合条件的区间或元素。但是这道题问的是恰好有多少个元素满足条件。
如果理解这个思路是怎么来的,代码就非常简单了,直接套用之前的模板即可。举个例子,如果请你找子数组里面最多3个不同元素的子数组的数量(A),和找子数组里面最多2个不同元素的子数组的数量(B),是不是两者的差就是子数组里面恰好有3个不同元素的数量呢?因为A里面一定包含了B的数量。
我这里提供hashmap和数组的两种实现,数组的实现速度会快很多。
时间O(n)
空间O(n)
Java hashmap实现,套用了诸多sliding window题目的模板
1 class Solution { 2 public int subarraysWithKDistinct(int[] A, int K) { 3 return helper(A, K) - helper(A, K - 1); 4 } 5 6 private int helper(int[] A, int K) { 7 int start = 0; 8 int end = 0; 9 int res = 0; 10 HashMap<Integer, Integer> map = new HashMap<>(); 11 while (end < A.length) { 12 if (map.getOrDefault(A[end], 0) == 0) { 13 K--; 14 } 15 map.put(A[end], map.getOrDefault(A[end], 0) + 1); 16 end++; 17 while (K < 0) { 18 map.put(A[start], map.get(A[start]) - 1); 19 if (map.get(A[start]) == 0) { 20 K++; 21 } 22 start++; 23 } 24 // 注意这里是累加,因为求的是子数组的数目的和 25 res += end - start + 1; 26 } 27 return res; 28 } 29 }
Java 数组实现
能用数组实现是因为题目里有这个条件,1 <= A[i] <= A.length。否则是没法确定数组长度的。
1 class Solution { 2 public int subarraysWithKDistinct(int[] A, int K) { 3 return helper(A, K) - helper(A, K - 1); 4 } 5 6 private int helper(int[] nums, int k) { 7 int len = nums.length; 8 int start = 0; 9 int end = 0; 10 int res = 0; 11 int[] map = new int[len + 1]; 12 while (end < len) { 13 if (map[nums[end]] == 0) { 14 k--; 15 } 16 map[nums[end]]++; 17 end++; 18 while (k < 0) { 19 map[nums[start]]--; 20 if (map[nums[start]] == 0) { 21 k++; 22 } 23 start++; 24 } 25 // 注意这里是累加,因为求的是子数组的数目的和 26 res += end - start + 1; 27 } 28 return res; 29 } 30 }
JavaScript实现
1 /** 2 * @param {number[]} A 3 * @param {number} K 4 * @return {number} 5 */ 6 var subarraysWithKDistinct = function (A, K) { 7 function atMostK(k) { 8 let l = 0; 9 let res = 0; 10 const count = {}; 11 12 for (let r = 0; r < A.length; r++) { 13 if (count[A[r]] == null) count[A[r]] = 0; 14 if (count[A[r]] === 0) k--; 15 count[A[r]]++; 16 17 while (k < 0) { 18 count[A[l]]--; 19 if (count[A[l]] === 0) k++; 20 l++; 21 } 22 // 注意这里是累加,因为求的是子数组的数目的和 23 res += r - l + 1; 24 } 25 return res; 26 } 27 return atMostK(K) - atMostK(K - 1); 28 };