題目
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,K 代表窗口能能包含的不同數字的個數。K = 2 代表窗口內只能有 2 個不同的數字。求數組中滿足條件 K 的窗口個數。
解題思路
如果只是單純的滑動窗口去做,會錯過一些解。比如在例子 1 中,滑動窗口可以得到 [1,2], [1,2,1], [1,2,1,2], [2,1,2], [1,2], [2,3], 會少 [2,1] 這個解,原因是右邊窗口滑動到最右邊了,左邊窗口在縮小的過程中,右邊窗口不會再跟着動了。有同學可能會説,每次左邊窗口移動的時候,右邊窗口都再次從左邊窗口的位置開始重新滑動。這樣做確實可以,但是這樣做完會發現超時。因為中間包含大量的重複計算。
這道題就需要第 3 個指針。原有滑動窗口的 2 個指針,右窗口保留這個窗口裏面最長的子數組,正好有 K 個元素,左窗口右移的邏輯不變。再多用一個指針用來標識正好有 K - 1 個元素的位置。那麼正好有 K 個不同元素的解就等於 ans = atMostK(A, K) - atMostK(A, K - 1)。最多有 K 個元素減去最多有 K - 1 個元素得到的窗口中正好有 K 個元素的解。
以例子 1 為例,先求最多有 K 個元素的窗口個數。
[1]
[1,2], [2]
[1,2,1], [2,1], [1]
[1,2,1,2], [2,1,2], [1,2], [2]
[2,3], [3]
每當窗口滑動到把 K 消耗為 0 的時候,res = right - left + 1 。為什麼要這麼計算,right - left + 1 代表的含義是,終點為 right,至多為 K 個元素的窗口有多少個。[left,right], [left + 1,right], [left + 2,right] …… [right,right]。這樣算出來的解是包含這道題最終求得的解的,還多出了一部分解。多出來的部分減掉即可,即減掉最多為 K - 1 個元素的解。
最多為 K - 1 個元素的解如下:
[1]
[2]
[1]
[2]
[3]
兩者相減以後得到的結果就是最終結果:
[1,2]
[1,2,1], [2,1]
[1,2,1,2], [2,1,2], [1,2]
[2,3]
參考代碼
package leetcode
func subarraysWithKDistinct(A []int, K int) int {
return subarraysWithKDistinctSlideWindow(A, K) - subarraysWithKDistinctSlideWindow(A, K-1)
}
func subarraysWithKDistinctSlideWindow(A []int, K int) int {
left, right, counter, res, freq := 0, 0, K, 0, map[int]int{}
for right = 0; right < len(A); right++ {
if freq[A[right]] == 0 {
counter--
}
freq[A[right]]++
for counter < 0 {
freq[A[left]]--
if freq[A[left]] == 0 {
counter++
}
left++
}
res += right - left + 1
}
return res
}