@@ -76,26 +76,214 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3300-3399/3318.Fi
7676
7777<!-- solution:start -->
7878
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 )
8090
8191<!-- tabs:start -->
8292
8393#### Python3
8494
8595``` 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
87150```
88151
89152#### Java
90153
91154``` 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+ }
93218```
94219
95220#### C++
96221
97222``` 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+ };
99287```
100288
101289#### Go
0 commit comments