leetcode- 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

题解

使用滑动窗口来确定某个区间的不同整数个数为k,当使用[i, j] 来滑动的时候会发现有漏掉的区间:比如当rest[i,j]=k时,此时如果滑动j, 则有可能漏掉[i1, j] && i1 > i; 如果滑动i的话就可能漏掉[i, j1] && j1>j。

由此可以看出,假如右端点不动,那么左端点是不唯一的,又因为随着左端的右移,个数一定是减少的,要想一直不变的话那么左端点的区间应该是连续的。

那么我们保持右端点不动(也可以让左端点不动),来计算可以有k个不同整数的左端点区间。

对于[i, j] 的不同整数为k的话,那么[i+1,j],[i+2,j],,,,[i+n,j] 都可能为k, 直到[i+n+1, j]的区间个数为k-1, 那么[i, i+n]都是符合要求的左端点

class Solution {
public:
    int subarraysWithKDistinct(vector<int>& nums, int k) {
        int len = nums.size();
        int vis1[20009];
        int vis2[20009];
        int k1 = 0, k2 = 0;
        int sum = 0;
        int left1 = 0, left2 = 0, right = 0;
        memset(vis1, 0, sizeof(vis1));
        memset(vis2, 0, sizeof(vis2));
        while(right < len) {
            if(!vis1[nums[right]]) k1++;
            vis1[nums[right]] ++;
            if(!vis2[nums[right]]) k2++;
            vis2[nums[right]] ++;

            while(k1 > k) {
                vis1[nums[left1]] --;
                if(!vis1[nums[left1]]) {
                    k1 --;
                }
                left1++;
            }

            while(k2 > k - 1) {
                vis2[nums[left2]] --;
                if(!vis2[nums[left2]]) {
                    k2 --;
                }
                left2++;
            }

            sum += left2 - left1;
            right++;

        }
        return sum;
    }
};

 

Guess you like

Origin blog.csdn.net/txgANG/article/details/119927847