[LeetCode] 992. Subarrays with K Different Integers 有K個不同整數的子數組



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: 12, 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. 1 <= A.length <= 20000
  2. 1 <= A[i] <= A.length
  3. 1 <= K <= A.length

這道題給了一個只有正整數的數組A,然后定義了一種好子數組,需要該子數組中不同的數字的個數正好為給定的正數K。這種玩子數組個數的題目,如果是求極值,大概率是要用動態規划做,不過這里是求滿足某個條件的子數組的個數,還有一種比較常見的解法,就是滑動窗口 Sliding Window,這是一種非常重要的解題思路,也經常在面試中出現,所以務必需要掌握。LeetCode 中關於滑動窗口的題還蠻多的,可以參見下方的類似題目區域,列出了一堆堆。在不遍歷所有子數組的情況下,求正好有K個不同的數字並不是很容易,這道題需要稍稍轉換一下思維,比較好求的求最多有K個不同的數字的情況。若能分別求出最多有K個不同數字的子數組的個數,和最多有 K-1 個不同數字的子數組的個數,二者相減,就是正好有K個不同數字的子數組的個數。我們之前做過這樣一道題目 Longest Substring with At Most K Distinct Characters,求最多有K個不同字符的最長子串,這里就是用的相同的滑動窗口的思路來做。

由於要同時求K和 K-1 的情況,所以可以用個子函數來做。在 helper 函數中,使用一個 HashMap 來建立每個數字和其出現次數之間的映射,再用個變量 left 標記窗口的左邊界。下面進行 for 循環,若當前的數字沒出現過,則K自減1,因為此時子數組中多了一個不同的數字,然后該數字的映射值自增1。此時K值有可能小於0了,說明子數組中的不同數字過多了,需要移除一個,用個 while 循環,若K小於0則進行循環,此時左邊界上的數字的映射值自減1,減小后若為0了,則說明該數字已經徹底被移出了滑動窗口,此時K應該自增1,同時左邊界 left 自增1,表示向右移動一位。此時這個窗口的長度就代表了此時最多有k個不同數字的子數組的個數,將其加入結果 res,這樣直至 for 循環退出后,就可以得到最終的結果了,參見代碼如下:


解法一:

class Solution {
public:
    int subarraysWithKDistinct(vector<int>& A, int K) {
        return helper(A, K) - helper(A, K - 1);
    }
    int helper(vector<int>& A, int K) {
        int n = A.size(), res = 0, left = 0;
        unordered_map<int, int> numCnt;
        for (int i = 0; i < n; ++i) {
            if (numCnt[A[i]] == 0) --K;
            ++numCnt[A[i]];
            while (K < 0) {
                if (--numCnt[A[left]] == 0) ++K;
                ++left;
            }
            res += i - left + 1;
        }
        return res;
    }
};

滑動窗口有多種寫法,比如下面這種並不直接減小K,而是用 HashMap 中的映射個數來跟K比較,不過這樣的話就一定要移除不在窗口內的映射才行,參見代碼如下:


解法二:

class Solution {
public:
    int subarraysWithKDistinct(vector<int>& A, int K) {
        return helper(A, K) - helper(A, K - 1);
    }
    int helper(vector<int>& A, int K) {
        int n = A.size(), res = 0, left = 0;
        unordered_map<int, int> numCnt;
        for (int i = 0; i < n; ++i) {
            ++numCnt[A[i]];
            while (numCnt.size() > K) {
                if (--numCnt[A[left]] == 0) numCnt.erase(A[left]);
                ++left;
            }
            res += i - left + 1;
        }
        return res;
    }
};

再來看另一種寫法,這里建立的是數字和其下標之間的映射,而不是其出現的個數,不過整體的思路並沒有啥太大的區別,參見代碼如下:


解法三:

class Solution {
public:
    int subarraysWithKDistinct(vector<int>& A, int K) {
        return helper(A, K) - helper(A, K - 1);
    }
    int helper(vector<int>& A, int K) {
        int n = A.size(), res = 0, left = 0;
        unordered_map<int, int> num2idx;
        for (int i = 0; i < n; ++i) {
            num2idx[A[i]] = i;
            while (num2idx.size() > K) {
                if (num2idx[A[left]] == left) num2idx.erase(A[left]);
                ++left;
            }
            res += i - left + 1;
        }
        return res;
    }
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/992


類似題目:

Number of Substrings Containing All Three Characters

Count Number of Nice Subarrays

Replace the Substring for Balanced String

Max Consecutive Ones III

Binary Subarrays With Sum

Fruit Into Baskets

Shortest Subarray with Sum at Least K

Minimum Size Subarray Sum

Longest Substring with At Most Two Distinct Characters

Longest Substring with At Least K Repeating Characters

Longest Substring with At Most K Distinct Characters


參考資料:

https://leetcode.com/problems/subarrays-with-k-different-integers/

https://leetcode.com/problems/subarrays-with-k-different-integers/discuss/523136/JavaC%2B%2BPython-Sliding-Window

https://leetcode.com/problems/subarrays-with-k-different-integers/discuss/235235/C%2B%2BJava-with-picture-prefixed-sliding-window


LeetCode All in One 題目講解匯總(持續更新中...)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM