[LeetCode] 992. Subarrays with K Different Integers

Given an integer array nums and an integer k, return the number of good subarrays of nums.

A good array is an array where the number of different integers in that array is exactly k.

  • For example, [1,2,3,1,2] has 3 different integers: 12, and 3.

A subarray is a contiguous part of an array.

Example 1:

Input: nums = [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: nums = [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].

Constraints:

  • 1 <= nums.length <= 2 * 104
  • 1 <= nums[i], k <= nums.length

K个不同整数的子数组。

给定一个正整数数组 nums和一个整数 k ,返回 num 中 「好子数组」 的数目。

如果 nums 的某个子数组中不同整数的个数恰好为 k,则称 nums 的这个连续、不一定不同的子数组为 「好子数组 」。

例如,[1,2,3,1,2] 中有 3 个不同的整数:1,2,以及 3。
子数组 是数组的 连续 部分。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/subarrays-with-k-different-integers
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题意是给定一个正整数数组 nums,如果 nums 的某个子数组中不同整数的个数恰好为 K,则称 nums 的这个连续、不一定独立的子数组为好子数组。返回 nums 中好子数组的数量。

思路依然是滑动窗口,但是这一题是没法直接套用76题的模板的,有一些变动(引用)。回忆前面做的滑动窗口的题目,有求过子数组里面最多K个不同元素的题(340),所以这个解法的思路是求子数组里面最多K个不同元素的子数组的数量子数组里面最多K - 1个不同元素的子数组的数量。之前能用76题的模板解决的题,一般都是在某一个范围内最多或者最少有几个符合条件的区间或元素。但是这道题问的是恰好有多少个元素满足条件。

如果理解这个思路是怎么来的,代码就非常简单了,直接套用之前的模板即可。举个例子,如果请你找子数组里面最多3个不同元素的子数组的数量(A),和找子数组里面最多2个不同元素的子数组的数量(B),是不是两者的差就是子数组里面恰好有3个不同元素的数量呢?因为A里面一定包含了B的数量。

我这里提供 hashmap 和数组的两种实现,数组的实现速度会快很多。

时间O(n)

空间O(n)

Java hashmap实现,套用了诸多sliding window题目的模板

 1 class Solution {
 2     public int subarraysWithKDistinct(int[] A, int K) {
 3         return helper(A, K) - helper(A, K - 1);
 4     }
 5 
 6     private int helper(int[] A, int K) {
 7         int start = 0;
 8         int end = 0;
 9         int res = 0;
10         HashMap<Integer, Integer> map = new HashMap<>();
11         while (end < A.length) {
12             if (map.getOrDefault(A[end], 0) == 0) {
13                 K--;
14             }
15             map.put(A[end], map.getOrDefault(A[end], 0) + 1);
16             end++;
17             while (K < 0) {
18                 map.put(A[start], map.get(A[start]) - 1);
19                 if (map.get(A[start]) == 0) {
20                     K++;
21                 }
22                 start++;
23             }
24             // 注意这里是累加,因为求的是子数组的数目的和
25             res += end - start + 1;
26         }
27         return res;
28     }
29 }

 

Java 数组实现

能用数组实现是因为题目里有这个条件,1 <= nums[i] <= A.length。否则是没法确定数组长度的。

 1 class Solution {
 2     public int subarraysWithKDistinct(int[] nums, int k) {
 3         return helper(nums, k) - helper(nums, k - 1);
 4     }
 5     
 6     private int helper(int[] nums, int k) {
 7         int len = nums.length;
 8         int start = 0;
 9         int end = 0;
10         int counter = 0;
11         int res = 0;
12         int[] map = new int[len + 1];
13         while (end < nums.length) {
14             if (map[nums[end]] == 0) {
15                 counter++;
16             }
17             map[nums[end]]++;
18             end++;
19             while (counter > k) {
20                 map[nums[start]]--;
21                 if (map[nums[start]] == 0) {
22                     counter--;
23                 }
24                 start++;
25             }
26             // 注意这里是累加,因为求的是子数组的数目的和
27             res += end - start;
28         }
29         return res;
30     }
31 }

 

JavaScript实现

 1 /**
 2  * @param {number[]} A
 3  * @param {number} K
 4  * @return {number}
 5  */
 6 var subarraysWithKDistinct = function (A, K) {
 7     function atMostK(k) {
 8         let l = 0;
 9         let res = 0;
10         const count = {};
11 
12         for (let r = 0; r < A.length; r++) {
13             if (count[A[r]] == null) count[A[r]] = 0;
14             if (count[A[r]] === 0) k--;
15             count[A[r]]++;
16 
17             while (k < 0) {
18                 count[A[l]]--;
19                 if (count[A[l]] === 0) k++;
20                 l++;
21             }
22             // 注意这里是累加,因为求的是子数组的数目的和
23             res += r - l + 1;
24         }
25         return res;
26     }
27     return atMostK(K) - atMostK(K - 1);
28 };

 

sliding window相关题目

LeetCode 题目总结

posted @ 2020-04-04 06:06  CNoodle  阅读(473)  评论(0编辑  收藏  举报