問題描述
給定一個正整數數組 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].
解題報告
考慮累加以每個數字結尾的好子數組的個數。
那麼如何計算以每個數字結尾的子數組的個數呢?
假設 [r,i]
是以 A[i]
結尾的好數組的最小區間,[l,i]
是以 A[i]
結尾的好數組的最大區間,
則每個累加 r-l+1
即可。
所以現在問題變成了 如何計算 l
和 r
。
l
意味着 [l,i]
的區間中不同整數的個數取不到 K+1
時,不開始更新 l
;
r
意味着 [r,i]
的區間中不同整數的個數剛取到 K
時,開始更新 r
。
想法其實挺簡單的,但是編碼實現時,總是不知如何下手,哎,還是要多多練習吧
這題和 Leetcode 1248. 統計「優美子數組」 的【滑動窗口解法】有着異曲同工之妙,只是 Leetcode 1248
中,數組中只有兩類數,奇數&偶數,所以我們不需要令設兩個數組來記錄窗口內的奇數和偶數。
實現代碼
代碼部分完全源自參考的文獻,侵權必刪
class Solution{
public:
int subarraysWithKDistinct(vector<int>&A, int K){
int n=A.size();
vector<int>cl(n+1, 0), cr(n+1, 0);
int l=0, r=0, ans=0, nl=0, nr=0;
for(int i=0;i<n;i++){
if(cl[A[i]]++==0) nl++;
while(nl>K){
if(--cl[A[l++]]==0) nl--;
}
if(cr[A[i]]++==0) nr++;
while(nr>=K){
if(--cr[A[r++]]==0) nr--;
}
ans+=(r-l);
}
return ans;
}
};
參考資料
[1] Leetcode 992. K 個不同整數的子數組
[2] 每日算法系列【LeetCode 992】K個不同整數的子數組
[3] Leetcode 1248. 統計「優美子數組」
[4] Leetcode 1248. 統計「優美子數組」【記錄奇數位置&滑動窗口&前綴和】