Skip to content

feat: add solutions to lc problems: No.3318,3321 #3642

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

196 changes: 192 additions & 4 deletions solution/3300-3399/3318.Find X-Sum of All K-Long Subarrays I/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,26 +76,214 @@ edit_url: https://github.com/doocs/leetcode/edit/main/solution/3300-3399/3318.Fi

<!-- solution:start -->

### 方法一
### 方法一:哈希表 + 有序集合

我们用一个哈希表 $\textit{cnt}$ 统计窗口中每个元素的出现次数,用一个有序集合 $\textit{l}$ 存储窗口中出现次数最多的 $x$ 个元素,用另一个有序集合 $\textit{r}$ 存储剩余的元素。

我们维护一个变量 $\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}$ 的值。继续遍历数组,直到遍历结束。

时间复杂度 $O(n \times \log k)$,空间复杂度 $O(n)$。其中 $n$ 为数组 $\textit{nums}$ 的长度。

相似题目:

- [3013. 将数组分成最小总代价的子数组 II](/solution/3000-3099/3013.Divide%20an%20Array%20Into%20Subarrays%20With%20Minimum%20Cost%20II/README.md)

<!-- tabs:start -->

#### Python3

```python

from sortedcontainers import SortedList


class Solution:
def findXSum(self, nums: List[int], k: int, x: int) -> List[int]:
def add(v: int):
if cnt[v] == 0:
return
p = (cnt[v], v)
if l and p > l[0]:
nonlocal s
s += p[0] * p[1]
l.add(p)
else:
r.add(p)

def remove(v: int):
if cnt[v] == 0:
return
p = (cnt[v], v)
if p in l:
nonlocal s
s -= p[0] * p[1]
l.remove(p)
else:
r.remove(p)

l = SortedList()
r = SortedList()
cnt = Counter()
s = 0
n = len(nums)
ans = [0] * (n - k + 1)
for i, v in enumerate(nums):
remove(v)
cnt[v] += 1
add(v)
j = i - k + 1
if j < 0:
continue
while r and len(l) < x:
p = r.pop()
l.add(p)
s += p[0] * p[1]
while len(l) > x:
p = l.pop(0)
s -= p[0] * p[1]
r.add(p)
ans[j] = s

remove(nums[j])
cnt[nums[j]] -= 1
add(nums[j])
return ans
```

#### Java

```java

class Solution {
private TreeSet<int[]> l = new TreeSet<>((a, b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]);
private TreeSet<int[]> r = new TreeSet<>(l.comparator());
private Map<Integer, Integer> cnt = new HashMap<>();
private int s;

public int[] findXSum(int[] nums, int k, int x) {
int n = nums.length;
int[] ans = new int[n - k + 1];
for (int i = 0; i < n; ++i) {
int v = nums[i];
remove(v);
cnt.merge(v, 1, Integer::sum);
add(v);
int j = i - k + 1;
if (j < 0) {
continue;
}
while (!r.isEmpty() && l.size() < x) {
var p = r.pollLast();
s += p[0] * p[1];
l.add(p);
}
while (l.size() > x) {
var p = l.pollFirst();
s -= p[0] * p[1];
r.add(p);
}
ans[j] = s;

remove(nums[j]);
cnt.merge(nums[j], -1, Integer::sum);
add(nums[j]);
}
return ans;
}

private void remove(int v) {
if (!cnt.containsKey(v)) {
return;
}
var p = new int[] {cnt.get(v), v};
if (l.contains(p)) {
l.remove(p);
s -= p[0] * p[1];
} else {
r.remove(p);
}
}

private void add(int v) {
if (!cnt.containsKey(v)) {
return;
}
var p = new int[] {cnt.get(v), v};
if (!l.isEmpty() && l.comparator().compare(l.first(), p) < 0) {
l.add(p);
s += p[0] * p[1];
} else {
r.add(p);
}
}
}
```

#### C++

```cpp

class Solution {
public:
vector<int> findXSum(vector<int>& nums, int k, int x) {
using pii = pair<int, int>;
set<pii> l, r;
int s = 0;
unordered_map<int, int> cnt;
auto add = [&](int v) {
if (cnt[v] == 0) {
return;
}
pii p = {cnt[v], v};
if (!l.empty() && p > *l.begin()) {
s += p.first * p.second;
l.insert(p);
} else {
r.insert(p);
}
};
auto remove = [&](int v) {
if (cnt[v] == 0) {
return;
}
pii p = {cnt[v], v};
auto it = l.find(p);
if (it != l.end()) {
s -= p.first * p.second;
l.erase(it);
} else {
r.erase(p);
}
};
vector<int> ans;
for (int i = 0; i < nums.size(); ++i) {
remove(nums[i]);
++cnt[nums[i]];
add(nums[i]);

int j = i - k + 1;
if (j < 0) {
continue;
}

while (!r.empty() && l.size() < x) {
pii p = *r.rbegin();
s += p.first * p.second;
r.erase(p);
l.insert(p);
}
while (l.size() > x) {
pii p = *l.begin();
s -= p.first * p.second;
l.erase(p);
r.insert(p);
}
ans.push_back(s);

remove(nums[j]);
--cnt[nums[j]];
add(nums[j]);
}
return ans;
}
};
```

#### Go
Expand Down
Loading
Loading