|
47 | 47 |
|
48 | 48 | <!-- 这里可写通用的实现逻辑 -->
|
49 | 49 |
|
| 50 | +**方法一:双指针** |
| 51 | + |
| 52 | +我们遍历数组 $nums$,对于每个 $i$,我们需要找到最小的 $j_1$,使得 $nums[j_1], nums[j_1 + 1], \dots, nums[i]$ 中不同的整数个数小于等于 $k$,以及最小的 $j_2$,使得 $nums[j_2], nums[j_2 + 1], \dots, nums[i]$ 中不同的整数个数小于等于 $k-1$。那么 $j_2 - j_1$ 就是以 $i$ 结尾的满足条件的子数组的个数。 |
| 53 | + |
| 54 | +在实现上,我们定义一个函数 $f(k)$,表示 $nums$ 中每个位置 $i$ 对应的最小的 $j$,使得 $nums[j], nums[j + 1], \dots, nums[i]$ 中不同的整数个数小于等于 $k$。该函数可以通过双指针实现,具体实现见代码。 |
| 55 | + |
| 56 | +然后我们调用 $f(k)$ 和 $f(k-1)$,计算出每个位置对应的 $j_1$ 和 $j_2$,然后计算出以每个位置 $i$ 结尾的满足条件的子数组的个数,最后求和即可。 |
| 57 | + |
| 58 | +时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 为数组 $nums$ 的长度。 |
| 59 | + |
50 | 60 | <!-- tabs:start -->
|
51 | 61 |
|
52 | 62 | ### **Python3**
|
53 | 63 |
|
54 | 64 | <!-- 这里可写当前语言的特殊实现逻辑 -->
|
55 | 65 |
|
56 | 66 | ```python
|
57 |
| - |
| 67 | +class Solution: |
| 68 | + def subarraysWithKDistinct(self, nums: List[int], k: int) -> int: |
| 69 | + def f(k): |
| 70 | + pos = [0] * len(nums) |
| 71 | + cnt = Counter() |
| 72 | + j = 0 |
| 73 | + for i, x in enumerate(nums): |
| 74 | + cnt[x] += 1 |
| 75 | + while len(cnt) > k: |
| 76 | + cnt[nums[j]] -= 1 |
| 77 | + if cnt[nums[j]] == 0: |
| 78 | + cnt.pop(nums[j]) |
| 79 | + j += 1 |
| 80 | + pos[i] = j |
| 81 | + return pos |
| 82 | + |
| 83 | + return sum(a - b for a, b in zip(f(k - 1), f(k))) |
58 | 84 | ```
|
59 | 85 |
|
60 | 86 | ### **Java**
|
61 | 87 |
|
62 | 88 | <!-- 这里可写当前语言的特殊实现逻辑 -->
|
63 | 89 |
|
64 | 90 | ```java
|
| 91 | +class Solution { |
| 92 | + public int subarraysWithKDistinct(int[] nums, int k) { |
| 93 | + int[] left = f(nums, k); |
| 94 | + int[] right = f(nums, k - 1); |
| 95 | + int ans = 0; |
| 96 | + for (int i = 0; i < nums.length; ++i) { |
| 97 | + ans += right[i] - left[i]; |
| 98 | + } |
| 99 | + return ans; |
| 100 | + } |
| 101 | + |
| 102 | + private int[] f(int[] nums, int k) { |
| 103 | + int n = nums.length; |
| 104 | + int[] cnt = new int[n + 1]; |
| 105 | + int[] pos = new int[n]; |
| 106 | + int s = 0; |
| 107 | + for (int i = 0, j = 0; i < n; ++i) { |
| 108 | + if (++cnt[nums[i]] == 1) { |
| 109 | + ++s; |
| 110 | + } |
| 111 | + for (; s > k; ++j) { |
| 112 | + if (--cnt[nums[j]] == 0) { |
| 113 | + --s; |
| 114 | + } |
| 115 | + } |
| 116 | + pos[i] = j; |
| 117 | + } |
| 118 | + return pos; |
| 119 | + } |
| 120 | +} |
| 121 | +``` |
| 122 | + |
| 123 | +### **C++** |
| 124 | + |
| 125 | +```cpp |
| 126 | +class Solution { |
| 127 | +public: |
| 128 | + int subarraysWithKDistinct(vector<int>& nums, int k) { |
| 129 | + vector<int> left = f(nums, k); |
| 130 | + vector<int> right = f(nums, k - 1); |
| 131 | + int ans = 0; |
| 132 | + for (int i = 0; i < nums.size(); ++i) { |
| 133 | + ans += right[i] - left[i]; |
| 134 | + } |
| 135 | + return ans; |
| 136 | + } |
| 137 | + |
| 138 | + vector<int> f(vector<int>& nums, int k) { |
| 139 | + int n = nums.size(); |
| 140 | + vector<int> pos(n); |
| 141 | + int cnt[n + 1]; |
| 142 | + memset(cnt, 0, sizeof(cnt)); |
| 143 | + int s = 0; |
| 144 | + for (int i = 0, j = 0; i < n; ++i) { |
| 145 | + if (++cnt[nums[i]] == 1) { |
| 146 | + ++s; |
| 147 | + } |
| 148 | + for (; s > k; ++j) { |
| 149 | + if (--cnt[nums[j]] == 0) { |
| 150 | + --s; |
| 151 | + } |
| 152 | + } |
| 153 | + pos[i] = j; |
| 154 | + } |
| 155 | + return pos; |
| 156 | + } |
| 157 | +}; |
| 158 | +``` |
65 | 159 |
|
| 160 | +### **Go** |
| 161 | + |
| 162 | +```go |
| 163 | +func subarraysWithKDistinct(nums []int, k int) (ans int) { |
| 164 | + f := func(k int) []int { |
| 165 | + n := len(nums) |
| 166 | + pos := make([]int, n) |
| 167 | + cnt := make([]int, n+1) |
| 168 | + s, j := 0, 0 |
| 169 | + for i, x := range nums { |
| 170 | + cnt[x]++ |
| 171 | + if cnt[x] == 1 { |
| 172 | + s++ |
| 173 | + } |
| 174 | + for ; s > k; j++ { |
| 175 | + cnt[nums[j]]-- |
| 176 | + if cnt[nums[j]] == 0 { |
| 177 | + s-- |
| 178 | + } |
| 179 | + } |
| 180 | + pos[i] = j |
| 181 | + } |
| 182 | + return pos |
| 183 | + } |
| 184 | + left, right := f(k), f(k-1) |
| 185 | + for i := range left { |
| 186 | + ans += right[i] - left[i] |
| 187 | + } |
| 188 | + return |
| 189 | +} |
66 | 190 | ```
|
67 | 191 |
|
68 | 192 | ### **...**
|
|
0 commit comments