2021年2月9日 Leetcode每日一题:992. K 个不同整数的子数组

K个不同整数的子数组

1.题目描述

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

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

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

2.示例

示例 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].

3.读题

这个题目的标题其实就说得很明白了,就是定义了一个概念叫做好数组,什么是好子数组呢,就是这个子数组里面包含的不同的整数个数恰好为给定值。
这里需要一提的是,子数组和子序列的区别。

子数组和子序列,都是从数组里截取一部分内容所组成的。
但是,子数组一般是从数组里截取连续的内容所组成的,子序列则没有这个限定,可以连续也可以不连续。

所以,这一题要寻找的目标有两个特征:连续,且包含K个不同的整数。我们需要求出数组里给定的目标的个数。

4.思路

一开始先用暴力法跑一下, 大致思路就是以每个值为起点,从后遍历,直到满足好子数组的条件就计数+1,然后继续往后遍历,再直到不满足条件了就跳出,选择下一个数为起点。大致代码如下:

class Solution {
     
    public int subarraysWithKDistinct(int[] A, int K) {
     
        int count = 0;
        for(int i=0;i<A.length;i++){
     
            int sum = 1;
            int[] map = new int[A.length+1];
            map[A[i]] = 1;
            for(int j=i+1;j<A.length;j++){
     
                if(sum==K){
     
                    count++;
                }else if(sum>K){
     
                    break;
                }
                if(map[A[j]]==0){
     
                    sum++;
                }
                map[A[j]]++;
            }
            if(sum==K) count++;
            map = new int[A.length+1];
        }
        return count;
    }
}

喜闻乐见地超时了,毕竟接近 O ( n 2 ) O(n^2) O(n2)的时间复杂度,在数组最长20000的条件下,超时也是预料之中。

然后就考虑用滑动窗口来做。但是滑动窗口一般比较好做的情况是,限定一个区间内最多有多少个不同的数或者最少有多少个不同的数,因此可以把题目的问题转化一下,可以分别求出最多有k个不同整数的子数组数量和最多有k-1个不同整数的子数组数量 ,然后用前者减去后者,得出的就是刚好有k个不同整数的子数组的数量。

一旦想到这一点,接下来的代码环节就变得很简单了。

5.代码

public class Solution {
     
    public int subarraysWithKDistinct(int[] A, int K) {
     
        return find(A,K) - find(A,K-1);
    }
    private int find(int[] A, int K) {
     
        int[] map = new int[A.length+1];
        int left = 0;
        int right = 0;
        int count = 0;
        int ans = 0;
        while (right<A.length){
     
            if (map[A[right]]==0) count++;
            map[A[right]]++;
            right++;
            while(count>K){
     
                map[A[left]]--;
                if (map[A[left]]==0) count--;
                left++;
            }
            ans+=(right-left);
        }
        return ans;
    }
}   

你可能感兴趣的:(leetcode每日一题,算法,java,leetcode)