LeetCode 992. K 個不同整數的子陣列(困難)
992. K 個不同整數的子陣列
給定一個正整數陣列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].
示例 2:
輸入:A = [1,2,1,3,4], K = 3 輸出:3 解釋:恰好由 3 個不同整陣列成的子陣列:[1,2,1,3], [2,1,3], [1,3,4].
提示:
1 <= A.length <= 20000
1 <= A[i] <= A.length
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)
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。