Leetcode 992 Subarrays with K Different Integers

题目链接:https://leetcode.com/problems/subarrays-with-k-different-integers/

题意:已知一个全为正数的数组A,1<=A.length<=20000,1<=A[i]<=A.length,1<=K<=A.length,问A中恰好有K个不同的元素的子数组个数有多少个

思路:对于考虑到数据范围较大,暴力显然不可取。对于每个位置i,如果用min_k[i] 表示起始位置为i的子数组存在k个元素的最小结束位置,用min_k_1[i] 表示起始位置为i的子数组存在k+1个不同的元素的最小结束位置,则对于起始位置为i、存在k个不同元素的的子数组的个数为min_k_1[i]-min_k[i]。

至于如何求min_k[i]呢(和求min_k_1的方法一样)呢,可以维护一个滑动窗口,左边界为i,当滑动窗口不同元素个数小于k时,向右移动右边界,当等于k时,则左边界变为i+1,刚好用来求min_k[i+1],min_k[i+1]>=min_k[i],因此可在线性的时间内求出min_k和min_k_1,滑动窗口的不同元素个数可以用map求(无序的话用inordered_map更好)。

class Solution {
public:
    int subarraysWithKDistinct(vector<int>& A, int K) {
        if (K > A.size()||K==0)
            return 0;int *min_k = new int[A.size()], *min_k_1 = new int[A.size()];
        cal_min(A,min_k,A.size(),K);     //计算min_k
        cal_min(A, min_k_1, A.size(), K + 1);  //计算min_k_1
        int ans = 0;
        for (int i = 0;i < A.size();i++) {
            if (min_k_1[i] + min_k[i] == -2)    //如果都未更新,则i起始的子数组不同元素个数一定小于K
                continue;
            else if(min_k_1[i]!=-1)         //min_k_1更新
                ans += min_k_1[i] - min_k[i];  
            else ans += A.size() - min_k[i];    //min_k_1未更新,min_k更新,最后一个元素依然长度为K
        }
        return ans;
    }
    void cal_min(vector<int>& A,int *Min,int len,int K) {
        map<int, int> mp;
        memset(Min, -1, 4 * len);
        for (int i = 0;i < K;i++)
            mp[A[i]]++;
        int l = 0, r = K - 1;
        while (r < A.size()) {
            while (mp.size() == K) {
                Min[l] = r;
                mp[A[l]]--;
                if (mp[A[l]] == 0)
                    mp.erase(A[l]);
                l++;
            }
            r++;
            if (r<A.size())
                mp[A[r]]++;
        }
    }
};

  

原文地址:https://www.cnblogs.com/dlutjwh/p/10730160.html