|
| 1 | +--- |
| 2 | +comments: true |
| 3 | +difficulty: 中等 |
| 4 | +edit_url: https://github.com/doocs/leetcode/edit/main/solution/3800-3899/3851.Maximum%20Requests%20Without%20Violating%20the%20Limit/README.md |
| 5 | +--- |
| 6 | + |
| 7 | +<!-- problem:start --> |
| 8 | + |
| 9 | +# [3851. Maximum Requests Without Violating the Limit 🔒](https://leetcode.cn/problems/maximum-requests-without-violating-the-limit) |
| 10 | + |
| 11 | +[English Version](/solution/3800-3899/3851.Maximum%20Requests%20Without%20Violating%20the%20Limit/README_EN.md) |
| 12 | + |
| 13 | +## 题目描述 |
| 14 | + |
| 15 | +<!-- description:start --> |
| 16 | + |
| 17 | +<p>You are given a 2D integer array <code>requests</code>, where <code>requests[i] = [user<sub>i</sub>, time<sub>i</sub>]</code> indicates that <code>user<sub>i</sub></code> made a request at <code>time<sub>i</sub></code>.</p> |
| 18 | + |
| 19 | +<p>You are also given two integers <code>k</code> and <code>window</code>.</p> |
| 20 | + |
| 21 | +<p>A user violates the limit if there exists an integer <code>t</code> such that the user makes strictly more than <code>k</code> requests in the inclusive interval <code>[t, t + window]</code>.</p> |
| 22 | + |
| 23 | +<p>You may drop any number of requests.</p> |
| 24 | + |
| 25 | +<p>Return an integer denoting the <strong>maximum</strong> number of requests that can <strong>remain</strong> such that no user violates the limit.</p> |
| 26 | + |
| 27 | +<p> </p> |
| 28 | +<p><strong class="example">Example 1:</strong></p> |
| 29 | + |
| 30 | +<div class="example-block"> |
| 31 | +<p><strong>Input:</strong> <span class="example-io">requests = [[1,1],[2,1],[1,7],[2,8]], k = 1, window = 4</span></p> |
| 32 | + |
| 33 | +<p><strong>Output:</strong> <span class="example-io">4</span></p> |
| 34 | + |
| 35 | +<p><strong>Explanation:</strong></p> |
| 36 | + |
| 37 | +<ul> |
| 38 | + <li>For user 1, the request times are <code>[1, 7]</code>. The difference between them is 6, which is greater than <code>window = 4</code>.</li> |
| 39 | + <li>For user 2, the request times are <code>[1, 8]</code>. The difference is 7, which is also greater than <code>window = 4</code>.</li> |
| 40 | + <li>No user makes more than <code>k = 1</code> request within any inclusive interval of length <code>window</code>. Therefore, all 4 requests can remain.</li> |
| 41 | +</ul> |
| 42 | +</div> |
| 43 | + |
| 44 | +<p><strong class="example">Example 2:</strong></p> |
| 45 | + |
| 46 | +<div class="example-block"> |
| 47 | +<p><strong>Input:</strong> <span class="example-io">requests = [[1,2],[1,5],[1,2],[1,6]], k = 2, window = 5</span></p> |
| 48 | + |
| 49 | +<p><strong>Output:</strong> <span class="example-io">2</span></p> |
| 50 | + |
| 51 | +<p><strong>Explanation:</strong></p> |
| 52 | + |
| 53 | +<ul> |
| 54 | + <li>For user 1, the request times are <code>[2, 2, 5, 6]</code>. The inclusive interval <code>[2, 7]</code> of length <code>window = 5</code> contains all 4 requests.</li> |
| 55 | + <li>Since 4 is strictly greater than <code>k = 2</code>, at least 2 requests must be removed.</li> |
| 56 | + <li>After removing any 2 requests, every inclusive interval of length <code>window</code> contains at most <code>k = 2</code> requests.</li> |
| 57 | + <li>Therefore, the maximum number of requests that can remain is 2.</li> |
| 58 | +</ul> |
| 59 | +</div> |
| 60 | + |
| 61 | +<p><strong class="example">Example 3:</strong></p> |
| 62 | + |
| 63 | +<div class="example-block"> |
| 64 | +<p><strong>Input:</strong> <span class="example-io">requests = [[1,1],[2,5],[1,2],[3,9]], k = 1, window = 1</span></p> |
| 65 | + |
| 66 | +<p><strong>Output:</strong> <span class="example-io">3</span></p> |
| 67 | + |
| 68 | +<p><strong>Explanation:</strong></p> |
| 69 | + |
| 70 | +<ul> |
| 71 | + <li>For user 1, the request times are <code>[1, 2]</code>. The difference is 1, which is equal to <code>window = 1</code>.</li> |
| 72 | + <li>The inclusive interval <code>[1, 2]</code> contains both requests, so the count is 2, which exceeds <code>k = 1</code>. One request must be removed.</li> |
| 73 | + <li>Users 2 and 3 each have only one request and do not violate the limit. Therefore, the maximum number of requests that can remain is 3.</li> |
| 74 | +</ul> |
| 75 | +</div> |
| 76 | + |
| 77 | +<p> </p> |
| 78 | +<p><strong>Constraints:</strong></p> |
| 79 | + |
| 80 | +<ul> |
| 81 | + <li><code>1 <= requests.length <= 10<sup>5</sup></code></li> |
| 82 | + <li><code>requests[i] = [user<sub>i</sub>, time<sub>i</sub>]</code></li> |
| 83 | + <li><code>1 <= k <= requests.length</code></li> |
| 84 | + <li><code>1 <= user<sub>i</sub>, time<sub>i</sub>, window <= 10<sup>5</sup></code></li> |
| 85 | +</ul> |
| 86 | + |
| 87 | +<!-- description:end --> |
| 88 | + |
| 89 | +## 解法 |
| 90 | + |
| 91 | +<!-- solution:start --> |
| 92 | + |
| 93 | +### 方法一:滑动窗口 + 双端队列 |
| 94 | + |
| 95 | +我们可以将请求按照用户进行分组,放在哈希表 $g$ 中,其中 $g[u]$ 是用户 $u$ 的请求时间列表。对于每个用户,我们需要从请求时间列表中删除一些请求,使得在任意长度为 $window$ 的区间内,剩余的请求数不超过 $k$。 |
| 96 | + |
| 97 | +对于用户 $u$ 的请求时间列表 $g[u]$,我们首先对其进行排序。然后,我们使用一个双端队列 $kept$ 来维护当前保留的请求时间。我们遍历请求时间列表中的每个请求时间 $t$,对于每个请求时间,我们需要将 $kept$ 中所有与 $t$ 的差值大于 $window$ 的请求时间删除掉。然后,我们将 $t$ 添加到 $kept$ 中。如果此时 $kept$ 中的请求数超过了 $k$,我们需要删除掉 $kept$ 中的最后一个请求时间,并增加删除的请求数。最后,我们将用户 $u$ 的请求数减去删除的请求数,累加到答案中。 |
| 98 | + |
| 99 | +时间复杂度 $O(n \log n)$,空间复杂度 $O(n)$,其中 $n$ 是请求的数量。每个请求被访问一次,排序需要 $O(n \log n)$ 的时间,哈希表和双端队列的操作需要 $O(n)$ 的时间。 |
| 100 | + |
| 101 | +<!-- tabs:start --> |
| 102 | + |
| 103 | +#### Python3 |
| 104 | + |
| 105 | +```python |
| 106 | +class Solution: |
| 107 | + def maxRequests(self, requests: list[list[int]], k: int, window: int) -> int: |
| 108 | + g = defaultdict(list) |
| 109 | + for u, t in requests: |
| 110 | + g[u].append(t) |
| 111 | + ans = 0 |
| 112 | + for ts in g.values(): |
| 113 | + ts.sort() |
| 114 | + kept = deque() |
| 115 | + deletions = 0 |
| 116 | + for t in ts: |
| 117 | + while kept and t - kept[0] > window: |
| 118 | + kept.popleft() |
| 119 | + kept.append(t) |
| 120 | + if len(kept) > k: |
| 121 | + kept.pop() |
| 122 | + deletions += 1 |
| 123 | + ans += len(ts) - deletions |
| 124 | + return ans |
| 125 | +``` |
| 126 | + |
| 127 | +#### Java |
| 128 | + |
| 129 | +```java |
| 130 | +class Solution { |
| 131 | + public int maxRequests(int[][] requests, int k, int window) { |
| 132 | + Map<Integer, List<Integer>> g = new HashMap<>(); |
| 133 | + for (int[] r : requests) { |
| 134 | + int u = r[0], t = r[1]; |
| 135 | + g.computeIfAbsent(u, x -> new ArrayList<>()).add(t); |
| 136 | + } |
| 137 | + |
| 138 | + int ans = 0; |
| 139 | + ArrayDeque<Integer> kept = new ArrayDeque<>(); |
| 140 | + |
| 141 | + for (List<Integer> ts : g.values()) { |
| 142 | + Collections.sort(ts); |
| 143 | + kept.clear(); |
| 144 | + int deletions = 0; |
| 145 | + |
| 146 | + for (int t : ts) { |
| 147 | + while (!kept.isEmpty() && t - kept.peekFirst() > window) { |
| 148 | + kept.pollFirst(); |
| 149 | + } |
| 150 | + kept.addLast(t); |
| 151 | + if (kept.size() > k) { |
| 152 | + kept.pollLast(); |
| 153 | + deletions++; |
| 154 | + } |
| 155 | + } |
| 156 | + ans += ts.size() - deletions; |
| 157 | + } |
| 158 | + return ans; |
| 159 | + } |
| 160 | +} |
| 161 | +``` |
| 162 | + |
| 163 | +#### C++ |
| 164 | + |
| 165 | +```cpp |
| 166 | +class Solution { |
| 167 | +public: |
| 168 | + int maxRequests(vector<vector<int>>& requests, int k, int window) { |
| 169 | + unordered_map<int, vector<int>> g; |
| 170 | + g.reserve(requests.size() * 2); |
| 171 | + |
| 172 | + for (auto& r : requests) { |
| 173 | + g[r[0]].push_back(r[1]); |
| 174 | + } |
| 175 | + |
| 176 | + int ans = 0; |
| 177 | + deque<int> kept; |
| 178 | + |
| 179 | + for (auto& [_, ts] : g) { |
| 180 | + sort(ts.begin(), ts.end()); |
| 181 | + kept.clear(); |
| 182 | + int deletions = 0; |
| 183 | + |
| 184 | + for (int t : ts) { |
| 185 | + while (!kept.empty() && t - kept.front() > window) { |
| 186 | + kept.pop_front(); |
| 187 | + } |
| 188 | + kept.push_back(t); |
| 189 | + if (kept.size() > k) { |
| 190 | + kept.pop_back(); |
| 191 | + deletions++; |
| 192 | + } |
| 193 | + } |
| 194 | + ans += ts.size() - deletions; |
| 195 | + } |
| 196 | + return ans; |
| 197 | + } |
| 198 | +}; |
| 199 | +``` |
| 200 | + |
| 201 | +#### Go |
| 202 | + |
| 203 | +```go |
| 204 | +func maxRequests(requests [][]int, k int, window int) (ans int) { |
| 205 | + g := make(map[int][]int) |
| 206 | + for _, r := range requests { |
| 207 | + u, t := r[0], r[1] |
| 208 | + g[u] = append(g[u], t) |
| 209 | + } |
| 210 | + for _, ts := range g { |
| 211 | + sort.Ints(ts) |
| 212 | + |
| 213 | + kept := make([]int, 0) |
| 214 | + head := 0 |
| 215 | + deletions := 0 |
| 216 | + |
| 217 | + for _, t := range ts { |
| 218 | + for head < len(kept) && t-kept[head] > window { |
| 219 | + head++ |
| 220 | + } |
| 221 | + kept = append(kept, t) |
| 222 | + if len(kept)-head > k { |
| 223 | + kept = kept[:len(kept)-1] |
| 224 | + deletions++ |
| 225 | + } |
| 226 | + } |
| 227 | + |
| 228 | + ans += len(ts) - deletions |
| 229 | + } |
| 230 | + return |
| 231 | +} |
| 232 | +``` |
| 233 | + |
| 234 | +#### TypeScript |
| 235 | + |
| 236 | +```ts |
| 237 | +function maxRequests(requests: number[][], k: number, window: number): number { |
| 238 | + const g = new Map<number, number[]>(); |
| 239 | + for (const [u, t] of requests) { |
| 240 | + if (!g.has(u)) g.set(u, []); |
| 241 | + g.get(u)!.push(t); |
| 242 | + } |
| 243 | + |
| 244 | + let ans = 0; |
| 245 | + |
| 246 | + for (const ts of g.values()) { |
| 247 | + ts.sort((a, b) => a - b); |
| 248 | + |
| 249 | + const kept: number[] = []; |
| 250 | + let head = 0; |
| 251 | + let deletions = 0; |
| 252 | + |
| 253 | + for (const t of ts) { |
| 254 | + while (head < kept.length && t - kept[head] > window) head++; |
| 255 | + kept.push(t); |
| 256 | + if (kept.length - head > k) { |
| 257 | + kept.pop(); |
| 258 | + deletions++; |
| 259 | + } |
| 260 | + } |
| 261 | + |
| 262 | + ans += ts.length - deletions; |
| 263 | + } |
| 264 | + |
| 265 | + return ans; |
| 266 | +} |
| 267 | +``` |
| 268 | + |
| 269 | +<!-- tabs:end --> |
| 270 | + |
| 271 | +<!-- solution:end --> |
| 272 | + |
| 273 | +<!-- problem:end --> |
0 commit comments