【滑动窗口】【leetcode】【困难】992. K 个不同整数的子数组

题目:

给定一个正整数数组 A,如果 A 的某个子数组中不同整数的个数恰好为 K,则称 A 的这个连续、不一定不同的子数组为好子数组。

(例如,[1,2,3,1,2] 中有 3 个不同的整数:1,2,以及 3。)

返回 A 中好子数组的数目。

例:

输入: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].

原题地址:

992. K 个不同整数的子数组

解题思路:

定义2个指针left和right,窗口[left, right)中的数据保存在一个map中,map[i]:代表窗口中数字i出现的次数。

  • 当map.size() < K时,右移right;
  • 当map.size() == K时,若right数据在map中,右移right;
  • 剩余情况说明,[left, right)是一个数量最多的好子数组(再多一个则不满足),此时缩小窗口右侧至数量最小的好子数组(再少一个不满足)后再恢复至原来的[left, right)后,右移left,缩小过程中计数。

移动过程如下(蓝底为窗口区域,橙底为right):

c++代码:

class Solution {
public:
    int subarraysWithKDistinct(vector<int>& A, int k) {
        int left = 0;
        int right = 0;
        map<int, int> freq; // 记录[left,right]内数字及其频次
        int total = 0;

        while (right < A.size()) {
            if (freq.size() < k) {
                add(freq, A[right++]);
                continue;
            }
            // freq.size() == k
            map<int, int>::iterator it = freq.find(A[right]);
            if (it != freq.end()) {
                ++it->second;
                right++;
                continue;
            }
            // freq.size() > k
            // [left, right)区间内含left的子数组
            int t = right - 1;
            while (freq.size() == k) {
                total++;
                remove(freq, A[t--]);
            }
            while (++t < right) {
                add(freq, A[t]);
            }
            remove(freq, A[left++]);
        }
        while (left < right) {
            int t = right - 1;
            while (freq.size() == k) {
                total++;
                remove(freq, A[t--]);
            }
            while (++t < right) {
                add(freq, A[t]);
            }
            remove(freq, A[left++]);
        }
        return total;
    }

    void add(map<int, int>& m, int k) {
        map<int, int>::iterator it = m.find(k);
        if (it == m.end()) {
            m[k] = 1;
        } else {
            ++it->second;
        }
    }
    void remove(map<int, int>& m, int k) {
        map<int, int>::iterator it = m.find(k);
        if (it == m.end()) return;
        if (it->second == 1) {
            m.erase(it);
        } else {
            --it->second;
        }
    }
};

猜你喜欢

转载自blog.csdn.net/hbuxiaoshe/article/details/114582452
今日推荐