@@ -76,26 +76,214 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3300-3399/3318.Fi
76
76
77
77
<!-- solution:start -->
78
78
79
- ### 方法一
79
+ ### 方法一:哈希表 + 有序集合
80
+
81
+ 我们用一个哈希表 $\textit{cnt}$ 统计窗口中每个元素的出现次数,用一个有序集合 $\textit{l}$ 存储窗口中出现次数最多的 $x$ 个元素,用另一个有序集合 $\textit{r}$ 存储剩余的元素。
82
+
83
+ 我们维护一个变量 $\textit{s}$ 表示 $\textit{l}$ 中元素的和。初始时,我们将前 $k$ 个元素加入到窗口中,并且更新有序集合 $\textit{l}$ 和 $\textit{r}$,并且计算 $\textit{s}$ 的值。如果 $\textit{l}$ 的大小小于 $x$,并且 $\textit{r}$ 不为空,我们就循环将 $\textit{r}$ 中的最大元素移动到 $\textit{l}$ 中,直到 $\textit{l}$ 的大小等于 $x$,过程中更新 $\textit{s}$ 的值。如果 $\textit{l}$ 的大小大于 $x$,我们就循环将 $\textit{l}$ 中的最小元素移动到 $\textit{r}$ 中,直到 $\textit{l}$ 的大小等于 $x$,过程中更新 $\textit{s}$ 的值。此时,我们就可以计算出当前窗口的 $\textit{x-sum}$,添加到答案数组中。然后我们将窗口的左边界元素移出,更新 $\textit{cnt}$,并且更新有序集合 $\textit{l}$ 和 $\textit{r}$,以及 $\textit{s}$ 的值。继续遍历数组,直到遍历结束。
84
+
85
+ 时间复杂度 $O(n \times \log k)$,空间复杂度 $O(n)$。其中 $n$ 为数组 $\textit{nums}$ 的长度。
86
+
87
+ 相似题目:
88
+
89
+ - [ 3013. 将数组分成最小总代价的子数组 II] ( /solution/3000-3099/3013.Divide%20an%20Array%20Into%20Subarrays%20With%20Minimum%20Cost%20II/README.md )
80
90
81
91
<!-- tabs:start -->
82
92
83
93
#### Python3
84
94
85
95
``` python
86
-
96
+ from sortedcontainers import SortedList
97
+
98
+
99
+ class Solution :
100
+ def findXSum (self , nums : List[int ], k : int , x : int ) -> List[int ]:
101
+ def add (v : int ):
102
+ if cnt[v] == 0 :
103
+ return
104
+ p = (cnt[v], v)
105
+ if l and p > l[0 ]:
106
+ nonlocal s
107
+ s += p[0 ] * p[1 ]
108
+ l.add(p)
109
+ else :
110
+ r.add(p)
111
+
112
+ def remove (v : int ):
113
+ if cnt[v] == 0 :
114
+ return
115
+ p = (cnt[v], v)
116
+ if p in l:
117
+ nonlocal s
118
+ s -= p[0 ] * p[1 ]
119
+ l.remove(p)
120
+ else :
121
+ r.remove(p)
122
+
123
+ l = SortedList()
124
+ r = SortedList()
125
+ cnt = Counter()
126
+ s = 0
127
+ n = len (nums)
128
+ ans = [0 ] * (n - k + 1 )
129
+ for i, v in enumerate (nums):
130
+ remove(v)
131
+ cnt[v] += 1
132
+ add(v)
133
+ j = i - k + 1
134
+ if j < 0 :
135
+ continue
136
+ while r and len (l) < x:
137
+ p = r.pop()
138
+ l.add(p)
139
+ s += p[0 ] * p[1 ]
140
+ while len (l) > x:
141
+ p = l.pop(0 )
142
+ s -= p[0 ] * p[1 ]
143
+ r.add(p)
144
+ ans[j] = s
145
+
146
+ remove(nums[j])
147
+ cnt[nums[j]] -= 1
148
+ add(nums[j])
149
+ return ans
87
150
```
88
151
89
152
#### Java
90
153
91
154
``` java
92
-
155
+ class Solution {
156
+ private TreeSet<int[]> l = new TreeSet<> ((a, b) - > a[0 ] == b[0 ] ? a[1 ] - b[1 ] : a[0 ] - b[0 ]);
157
+ private TreeSet<int[]> r = new TreeSet<> (l. comparator());
158
+ private Map<Integer , Integer > cnt = new HashMap<> ();
159
+ private int s;
160
+
161
+ public int [] findXSum (int [] nums , int k , int x ) {
162
+ int n = nums. length;
163
+ int [] ans = new int [n - k + 1 ];
164
+ for (int i = 0 ; i < n; ++ i) {
165
+ int v = nums[i];
166
+ remove(v);
167
+ cnt. merge(v, 1 , Integer :: sum);
168
+ add(v);
169
+ int j = i - k + 1 ;
170
+ if (j < 0 ) {
171
+ continue ;
172
+ }
173
+ while (! r. isEmpty() && l. size() < x) {
174
+ var p = r. pollLast();
175
+ s += p[0 ] * p[1 ];
176
+ l. add(p);
177
+ }
178
+ while (l. size() > x) {
179
+ var p = l. pollFirst();
180
+ s -= p[0 ] * p[1 ];
181
+ r. add(p);
182
+ }
183
+ ans[j] = s;
184
+
185
+ remove(nums[j]);
186
+ cnt. merge(nums[j], - 1 , Integer :: sum);
187
+ add(nums[j]);
188
+ }
189
+ return ans;
190
+ }
191
+
192
+ private void remove (int v ) {
193
+ if (! cnt. containsKey(v)) {
194
+ return ;
195
+ }
196
+ var p = new int [] {cnt. get(v), v};
197
+ if (l. contains(p)) {
198
+ l. remove(p);
199
+ s -= p[0 ] * p[1 ];
200
+ } else {
201
+ r. remove(p);
202
+ }
203
+ }
204
+
205
+ private void add (int v ) {
206
+ if (! cnt. containsKey(v)) {
207
+ return ;
208
+ }
209
+ var p = new int [] {cnt. get(v), v};
210
+ if (! l. isEmpty() && l. comparator(). compare(l. first(), p) < 0 ) {
211
+ l. add(p);
212
+ s += p[0 ] * p[1 ];
213
+ } else {
214
+ r. add(p);
215
+ }
216
+ }
217
+ }
93
218
```
94
219
95
220
#### C++
96
221
97
222
``` cpp
98
-
223
+ class Solution {
224
+ public:
225
+ vector<int > findXSum(vector<int >& nums, int k, int x) {
226
+ using pii = pair<int, int>;
227
+ set<pii > l, r;
228
+ int s = 0;
229
+ unordered_map<int, int> cnt;
230
+ auto add = [ &] (int v) {
231
+ if (cnt[ v] == 0) {
232
+ return;
233
+ }
234
+ pii p = {cnt[ v] , v};
235
+ if (!l.empty() && p > * l.begin()) {
236
+ s += p.first * p.second;
237
+ l.insert(p);
238
+ } else {
239
+ r.insert(p);
240
+ }
241
+ };
242
+ auto remove = [ &] (int v) {
243
+ if (cnt[ v] == 0) {
244
+ return;
245
+ }
246
+ pii p = {cnt[ v] , v};
247
+ auto it = l.find(p);
248
+ if (it != l.end()) {
249
+ s -= p.first * p.second;
250
+ l.erase(it);
251
+ } else {
252
+ r.erase(p);
253
+ }
254
+ };
255
+ vector<int > ans;
256
+ for (int i = 0; i < nums.size(); ++i) {
257
+ remove(nums[ i] );
258
+ ++cnt[ nums[ i]] ;
259
+ add(nums[ i] );
260
+
261
+ int j = i - k + 1;
262
+ if (j < 0) {
263
+ continue;
264
+ }
265
+
266
+ while (!r.empty() && l.size() < x) {
267
+ pii p = *r.rbegin();
268
+ s += p.first * p.second;
269
+ r.erase(p);
270
+ l.insert(p);
271
+ }
272
+ while (l.size() > x) {
273
+ pii p = *l.begin();
274
+ s -= p.first * p.second;
275
+ l.erase(p);
276
+ r.insert(p);
277
+ }
278
+ ans.push_back(s);
279
+
280
+ remove (nums[ j] );
281
+ --cnt[ nums[ j]] ;
282
+ add(nums[ j] );
283
+ }
284
+ return ans;
285
+ }
286
+ };
99
287
```
100
288
101
289
#### Go
0 commit comments