1. 程式人生 > 其它 >LeetCode 992. K 個不同整數的子陣列(困難)

LeetCode 992. K 個不同整數的子陣列(困難)

技術標籤:LeetCodeleetcode

992. K 個不同整數的子陣列

給定一個正整數陣列A,如果A的某個子陣列中不同整數的個數恰好為K,則稱A的這個連續、不一定不同的子陣列為好子陣列

(例如,[1,2,3,1,2]中有3個不同的整數:12,以及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].

示例 2:

輸入:A = [1,2,1,3,4], K = 3
輸出:
3 解釋:恰好由 3 個不同整陣列成的子陣列:[1,2,1,3], [2,1,3], [1,3,4].

提示:

  1. 1 <= A.length <= 20000
  2. 1 <= A[i] <= A.length
  3. 1 <= K <= A.length

我的Java程式碼:

思路:雖然是雙指標,但類似於雙迴圈。用num記錄子陣列中元素個數,當某個元素第一次出現的時候num++。當 num = K 時,即找到一個符合條件的子陣列。當內層迴圈結束如果 num < K,則剩下的子陣列中不會有滿足條件的子陣列,跳出迴圈。效率很低。

class Solution {
    public int subarraysWithKDistinct(int[] A, int K) {
		int sum = 0;
		int head, rear;
		for(head = 0;head < A.length-K+1;head++) {
			rear = head;
			int num = 0;
			int[] nums = new int[A.length];
			while(rear < A.length) {
				if(nums[A[rear]-1] == 0) {
					num++;
				}
				nums[A[rear]-1]++;
				if(num == K) {
					sum++;
				}else if(num > K) {
					break;
				}
				rear++;
			}
            if(num < K){
                break;
            }
		}
		return sum;
    }
}

學習別人的程式碼:

作者:LeetCode
連結:https://leetcode-cn.com/problems/subarrays-with-k-different-integers/solution/k-ge-bu-tong-zheng-shu-de-zi-shu-zu-by-l-ud34/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。

思路:

把原問題轉換成為容易求解的問題
友情提示:這裡把 「恰好」 轉換成為 「最多」須要一點求解「雙指標(滑動視窗)」問題的經驗。建立在熟練掌握這一類問題求解思路的基礎上。

把「恰好」改成「最多」就可以使用雙指標一前一後交替向右的方法完成,這是因為 對於每一個確定的左邊界,最多包含 K 種不同整數的右邊界是唯一確定的

,並且在左邊界向右移動的過程中,右邊界或者在原來的地方,或者在原來地方的右邊。

而「最多存在 K 個不同整數的子區間的個數」與「恰好存在 K 個不同整數的子區間的個數」的差恰好等於「最多存在 K - 1個不同整數的子區間的個數」。

因為原問題就轉換成為求解「最多存在 K 個不同整數的子區間的個數」與 「最多存在 K - 1個不同整數的子區間的個數」,它們其實是一個問題。

方法:雙指標(滑動視窗)
實現函式 atMostWithKDistinct(A, K) ,表示「最多存在 K個不同整數的子區間的個數」。於是 atMostWithKDistinct(A, K) - atMostWithKDistinct(A, K - 1) 即為所求。

public class Solution {

    public int subarraysWithKDistinct(int[] A, int K) {
        return atMostKDistinct(A, K) - atMostKDistinct(A, K - 1);
    }

    /**
     * @param A
     * @param K
     * @return 最多包含 K 個不同整數的子區間的個數
     */
    private int atMostKDistinct(int[] A, int K) {
        int len = A.length;
        int[] freq = new int[len + 1];

        int left = 0;
        int right = 0;
        // [left, right) 裡不同整數的個數
        int count = 0;
        int res = 0;
        // [left, right) 包含不同整數的個數小於等於 K
        while (right < len) {
            if (freq[A[right]] == 0) {
                count++;
            }
            freq[A[right]]++;
            right++;

            while (count > K) {
                freq[A[left]]--;
                if (freq[A[left]] == 0) {
                    count--;
                }
                left++;
            }
            // [left, right) 區間的長度就是對結果的貢獻
            res += right - left;
        }
        return res;
    }
}

作者:LeetCode
連結:https://leetcode-cn.com/problems/subarrays-with-k-different-integers/solution/k-ge-bu-tong-zheng-shu-de-zi-shu-zu-by-l-ud34/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。