Subarrays with K Different Integers

題目
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].

*思路

這個題是思考過程可以從暴力O(n^2)解法evolve到三指針的O(n)解法

暴力解法是首先用一個循環(huán)遍歷數組的每個元素i
For every starting point i, try to find number of valid subarrays starting from i
例如[1,2,2], K = 2
i = 0時,我們可以得出的valid subarrays有[1,2]和[1,2,2]這2個
Do this for every i in array A, you'll get the answer

暴力解法的缺點是當正在遍歷元素 i 時,你每次都得用另一個指針j從i的位置開始遍歷后面的所有元素才能知道有哪些valid subarrays。所以時間復雜度是O(n^2)

可以看出每次遍歷一個新的元素i,指針j總是得回撤到i的位置然后開始遍歷后面的元素
雙指針的算法多數都是利用求解答案的某些特性,讓我們無需回撤指針從而達到降低一個級別的時間復雜度

例如[1,2,1,2,3], K = 2
i = 0時, valid subarrays有[1,2], [1,2,1], [1,2,1,2] (一共3個)
我們可以有一根指針left讓它指向從i開始第一個遇到的valid subarray的末端(用一個dict1 keep track of number of distinct numbers in A[i...left], 如果len(dict1)等于K,則找到了left的位置)

用一根right指針指向最后一個遇到的valid subarray的末端(用一個dict2 keep track of number of distinct numbers in A[i...right], 如果len(dict2)等于K,而且right如果再向右移動就會導致len(dict2) > K)
在我們的這個例子input里,left = 1, right = 3

那么你會發(fā)現
number of valid subarrays starting from i is just equal to right - left + 1 = 3 - 1 + 1 = 3
這3個valid subarrays分別是A[i...left], A[i...left+1], A[i...right]

i = 1時
也需要找到相對于i = 1的對應的left和right指針,就可以計算出number of valid subarrays starting from i
當i = 1時,我們就不用考慮A[0]。A[0...left]本來是valid的,但是A[1...left]就不一定valid了。
所以left指針要向右邊探,使得A[1...left]也變得valid。同理right指針要向右移動使得A[1...right]變得valid。
當重新計算出相對于i = 1的對應的left和right指針,我們又知道了number of valid subarrays starting from i = 1了

以此類推遍歷完i = 0,1,2...n就行了
期間涉及到3個指針(i, left, right),由于他們全程都只需要向右移動,直到數組結尾,所以時間復雜度是O(n)

答案

class Solution(object):
    def subarraysWithKDistinct(self, A, K):
        """
        :type A: List[int]
        :type K: int
        :rtype: int
        """
        # window[number] -> occurrences of number
        window1 = {}
        window2 = {}
        
        ans = 0
        left, right = 0, 0
        for i in range(len(A)):
            # Move left pointer to closet place s.t [i...left] has exactly K distinct chars
            # Move right pointer to as far as possible s.t [i...right] has exactly K distinct chars
            while left < len(A):
                if len(window1) == K:
                    break
                window1[A[left]] = window1.get(A[left], 0) + 1
                left += 1
            if len(window1) < K:
                continue
                
            while right < len(A):
                if len(window2) == K:
                    break
                window2[A[right]] = window2.get(A[right], 0) + 1
                right += 1

            while right < len(A):
                if A[right] not in window2:
                    break
                else:
                    window2[A[right]] = window2.get(A[right], 0) + 1
                    right += 1
            
            ans += (right - left + 1)

            window1[A[i]] -= 1
            if window1[A[i]] == 0:
                window1.pop(A[i])

            window2[A[i]] -= 1
            if window2[A[i]] == 0:
                window2.pop(A[i])
             
        return ans
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內容