Skip to content

Commit bf876cb

Browse files
authored
feat: add solutions to lc problems: No.3318,3321 (doocs#3642)
* No.3318.Find X-Sum of All K-Long Subarrays I * No.3321.Find X-Sum of All K-Long Subarrays II
1 parent 3bdfd2a commit bf876cb

File tree

11 files changed

+1801
-16
lines changed

11 files changed

+1801
-16
lines changed

solution/3000-3099/3013.Divide an Array Into Subarrays With Minimum Cost II/README.md

+671
Large diffs are not rendered by default.

solution/3300-3399/3318.Find X-Sum of All K-Long Subarrays I/README.md

+192-4
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)