|
| 1 | +--- |
| 2 | +comments: true |
| 3 | +difficulty: 中等 |
| 4 | +edit_url: https://github.com/doocs/leetcode/edit/main/solution/3700-3799/3763.Maximum%20Total%20Sum%20with%20Threshold%20Constraints/README.md |
| 5 | +--- |
| 6 | + |
| 7 | +<!-- problem:start --> |
| 8 | + |
| 9 | +# [3763. Maximum Total Sum with Threshold Constraints 🔒](https://leetcode.cn/problems/maximum-total-sum-with-threshold-constraints) |
| 10 | + |
| 11 | +[English Version](/solution/3700-3799/3763.Maximum%20Total%20Sum%20with%20Threshold%20Constraints/README_EN.md) |
| 12 | + |
| 13 | +## 题目描述 |
| 14 | + |
| 15 | +<!-- description:start --> |
| 16 | + |
| 17 | +<p>You are given two integer arrays <code>nums</code> and <code>threshold</code>, both of length <code>n</code>.</p> |
| 18 | + |
| 19 | +<p>Starting at <code>step = 1</code>, you perform the following repeatedly:</p> |
| 20 | + |
| 21 | +<ul> |
| 22 | + <li>Choose an <strong>unused</strong> index <code>i</code> such that <code>threshold[i] <= step</code>. |
| 23 | + |
| 24 | + <ul> |
| 25 | + <li>If no such index exists, the process ends.</li> |
| 26 | + </ul> |
| 27 | + </li> |
| 28 | + <li>Add <code>nums[i]</code> to your running total.</li> |
| 29 | + <li>Mark index <code>i</code> as used and increment <code>step</code> by 1.</li> |
| 30 | + |
| 31 | +</ul> |
| 32 | + |
| 33 | +<p>Return the <strong>maximum</strong> <strong>total sum</strong> you can obtain by choosing indices optimally.</p> |
| 34 | + |
| 35 | +<p> </p> |
| 36 | +<p><strong class="example">Example 1:</strong></p> |
| 37 | + |
| 38 | +<div class="example-block"> |
| 39 | +<p><strong>Input:</strong> <span class="example-io">nums = [1,10,4,2,1,6], threshold = [5,1,5,5,2,2]</span></p> |
| 40 | + |
| 41 | +<p><strong>Output:</strong> <span class="example-io">17</span></p> |
| 42 | + |
| 43 | +<p><strong>Explanation:</strong></p> |
| 44 | + |
| 45 | +<ul> |
| 46 | + <li>At <code>step = 1</code>, choose <code>i = 1</code> since <code>threshold[1] <= step</code>. The total sum becomes 10. Mark index 1.</li> |
| 47 | + <li>At <code>step = 2</code>, choose <code>i = 4</code> since <code>threshold[4] <= step</code>. The total sum becomes 11. Mark index 4.</li> |
| 48 | + <li>At <code>step = 3</code>, choose <code>i = 5</code> since <code>threshold[5] <= step</code>. The total sum becomes 17. Mark index 5.</li> |
| 49 | + <li>At <code>step = 4</code>, we cannot choose indices 0, 2, or 3 because their thresholds are <code>> 4</code>, so we end the process.</li> |
| 50 | +</ul> |
| 51 | +</div> |
| 52 | + |
| 53 | +<p><strong class="example">Example 2:</strong></p> |
| 54 | + |
| 55 | +<div class="example-block"> |
| 56 | +<p><strong>Input:</strong> <span class="example-io">nums = [4,1,5,2,3], threshold = [3,3,2,3,3]</span></p> |
| 57 | + |
| 58 | +<p><strong>Output:</strong> <span class="example-io">0</span></p> |
| 59 | + |
| 60 | +<p><strong>Explanation:</strong></p> |
| 61 | + |
| 62 | +<p>At <code>step = 1</code> there is no index <code>i</code> with <code>threshold[i] <= 1</code>, so the process ends immediately. Thus, the total sum is 0.</p> |
| 63 | +</div> |
| 64 | + |
| 65 | +<p><strong class="example">Example 3:</strong></p> |
| 66 | + |
| 67 | +<div class="example-block"> |
| 68 | +<p><strong>Input:</strong> <span class="example-io">nums = [2,6,10,13], threshold = [2,1,1,1]</span></p> |
| 69 | + |
| 70 | +<p><strong>Output:</strong> <span class="example-io">31</span></p> |
| 71 | + |
| 72 | +<p><strong>Explanation:</strong></p> |
| 73 | + |
| 74 | +<ul> |
| 75 | + <li>At <code>step = 1</code>, choose <code>i = 3</code> since <code>threshold[3] <= step</code>. The total sum becomes 13. Mark index 3.</li> |
| 76 | + <li>At <code>step = 2</code>, choose <code>i = 2</code> since <code>threshold[2] <= step</code>. The total sum becomes 23. Mark index 2.</li> |
| 77 | + <li>At <code>step = 3</code>, choose <code>i = 1</code> since <code>threshold[1] <= step</code>. The total sum becomes 29. Mark index 1.</li> |
| 78 | + <li>At <code>step = 4</code>, choose <code>i = 0</code> since <code>threshold[0] <= step</code>. The total sum becomes 31. Mark index 0.</li> |
| 79 | + <li>After <code>step = 4</code> all indices have been chosen, so the process ends.</li> |
| 80 | +</ul> |
| 81 | +</div> |
| 82 | + |
| 83 | +<p> </p> |
| 84 | +<p><strong>Constraints:</strong></p> |
| 85 | + |
| 86 | +<ul> |
| 87 | + <li><code>n == nums.length == threshold.length</code></li> |
| 88 | + <li><code>1 <= n <= 10<sup>5</sup></code></li> |
| 89 | + <li><code>1 <= nums[i] <= 10<sup>9</sup></code></li> |
| 90 | + <li><code>1 <= threshold[i] <= n</code></li> |
| 91 | +</ul> |
| 92 | + |
| 93 | +<!-- description:end --> |
| 94 | + |
| 95 | +## 解法 |
| 96 | + |
| 97 | +<!-- solution:start --> |
| 98 | + |
| 99 | +### 方法一:贪心 + 排序 |
| 100 | + |
| 101 | +我们注意到,在每一个步骤中,我们都希望选择一个满足条件的数中最大的数加入总和中。因此,我们可以使用贪心的方法来解决这个问题。 |
| 102 | + |
| 103 | +我们首先将长度为 $n$ 的下标数组 $\textit{idx}$ 按照对应的阈值从小到大进行排序。然后,我们使用有序集合或优先队列(最大堆)来维护当前满足条件的数。在每一个步骤中,我们将所有阈值小于等于当前步骤数的数加入有序集合或优先队列中,然后选择其中最大的数加入总和中。如果此时有序集合或优先队列为空,说明没有满足条件的数,我们就结束过程。 |
| 104 | + |
| 105 | +时间复杂度 $O(n \times \log n)$,空间复杂度 $O(n)$。其中 $n$ 为数组 $\textit{nums}$ 的长度。 |
| 106 | + |
| 107 | +<!-- tabs:start --> |
| 108 | + |
| 109 | +#### Python3 |
| 110 | + |
| 111 | +```python |
| 112 | +class Solution: |
| 113 | + def maxSum(self, nums: List[int], threshold: List[int]) -> int: |
| 114 | + n = len(nums) |
| 115 | + idx = sorted(range(n), key=lambda i: threshold[i]) |
| 116 | + sl = SortedList() |
| 117 | + step = 1 |
| 118 | + ans = i = 0 |
| 119 | + while True: |
| 120 | + while i < n and threshold[idx[i]] <= step: |
| 121 | + sl.add(nums[idx[i]]) |
| 122 | + i += 1 |
| 123 | + if not sl: |
| 124 | + break |
| 125 | + ans += sl.pop() |
| 126 | + step += 1 |
| 127 | + return ans |
| 128 | +``` |
| 129 | + |
| 130 | +#### Java |
| 131 | + |
| 132 | +```java |
| 133 | +class Solution { |
| 134 | + public long maxSum(int[] nums, int[] threshold) { |
| 135 | + int n = nums.length; |
| 136 | + Integer[] idx = new Integer[n]; |
| 137 | + Arrays.setAll(idx, i -> i); |
| 138 | + Arrays.sort(idx, Comparator.comparingInt(i -> threshold[i])); |
| 139 | + TreeMap<Integer, Integer> tm = new TreeMap<>(); |
| 140 | + long ans = 0; |
| 141 | + for (int i = 0, step = 1;; ++step) { |
| 142 | + while (i < n && threshold[idx[i]] <= step) { |
| 143 | + tm.merge(nums[idx[i]], 1, Integer::sum); |
| 144 | + ++i; |
| 145 | + } |
| 146 | + if (tm.isEmpty()) { |
| 147 | + break; |
| 148 | + } |
| 149 | + int x = tm.lastKey(); |
| 150 | + ans += x; |
| 151 | + if (tm.merge(x, -1, Integer::sum) == 0) { |
| 152 | + tm.remove(x); |
| 153 | + } |
| 154 | + } |
| 155 | + return ans; |
| 156 | + } |
| 157 | +} |
| 158 | +``` |
| 159 | + |
| 160 | +#### C++ |
| 161 | + |
| 162 | +```cpp |
| 163 | +class Solution { |
| 164 | +public: |
| 165 | + long long maxSum(vector<int>& nums, vector<int>& threshold) { |
| 166 | + int n = nums.size(); |
| 167 | + vector<int> idx(n); |
| 168 | + iota(idx.begin(), idx.end(), 0); |
| 169 | + sort(idx.begin(), idx.end(), [&](int a, int b) { return threshold[a] < threshold[b]; }); |
| 170 | + |
| 171 | + multiset<int> ms; |
| 172 | + long long ans = 0; |
| 173 | + int i = 0; |
| 174 | + |
| 175 | + for (int step = 1;; ++step) { |
| 176 | + while (i < n && threshold[idx[i]] <= step) { |
| 177 | + ms.insert(nums[idx[i]]); |
| 178 | + ++i; |
| 179 | + } |
| 180 | + if (ms.empty()) { |
| 181 | + break; |
| 182 | + } |
| 183 | + |
| 184 | + auto it = prev(ms.end()); |
| 185 | + ans += *it; |
| 186 | + ms.erase(it); |
| 187 | + } |
| 188 | + return ans; |
| 189 | + } |
| 190 | +}; |
| 191 | +``` |
| 192 | + |
| 193 | +#### Go |
| 194 | + |
| 195 | +```go |
| 196 | +func maxSum(nums []int, threshold []int) int64 { |
| 197 | + n := len(nums) |
| 198 | + idx := make([]int, n) |
| 199 | + for i := 0; i < n; i++ { |
| 200 | + idx[i] = i |
| 201 | + } |
| 202 | + sort.Slice(idx, func(a, b int) bool { |
| 203 | + return threshold[idx[a]] < threshold[idx[b]] |
| 204 | + }) |
| 205 | + |
| 206 | + tree := redblacktree.NewWithIntComparator() |
| 207 | + var ans int64 |
| 208 | + i := 0 |
| 209 | + |
| 210 | + for step := 1; ; step++ { |
| 211 | + for i < n && threshold[idx[i]] <= step { |
| 212 | + val := nums[idx[i]] |
| 213 | + if cnt, found := tree.Get(val); found { |
| 214 | + tree.Put(val, cnt.(int)+1) |
| 215 | + } else { |
| 216 | + tree.Put(val, 1) |
| 217 | + } |
| 218 | + i++ |
| 219 | + } |
| 220 | + if tree.Empty() { |
| 221 | + break |
| 222 | + } |
| 223 | + |
| 224 | + node := tree.Right() |
| 225 | + key := node.Key.(int) |
| 226 | + cnt := node.Value.(int) |
| 227 | + |
| 228 | + ans += int64(key) |
| 229 | + if cnt == 1 { |
| 230 | + tree.Remove(key) |
| 231 | + } else { |
| 232 | + tree.Put(key, cnt-1) |
| 233 | + } |
| 234 | + } |
| 235 | + |
| 236 | + return ans |
| 237 | +} |
| 238 | +``` |
| 239 | + |
| 240 | +#### TypeScript |
| 241 | + |
| 242 | +```ts |
| 243 | +function maxSum(nums: number[], threshold: number[]): number { |
| 244 | + const n = nums.length; |
| 245 | + const idx = Array.from({ length: n }, (_, i) => i).sort((a, b) => threshold[a] - threshold[b]); |
| 246 | + const pq = new MaxPriorityQueue<number>(); |
| 247 | + let ans = 0; |
| 248 | + for (let i = 0, step = 1; ; ++step) { |
| 249 | + while (i < n && threshold[idx[i]] <= step) { |
| 250 | + pq.enqueue(nums[idx[i]]); |
| 251 | + ++i; |
| 252 | + } |
| 253 | + if (pq.isEmpty()) { |
| 254 | + break; |
| 255 | + } |
| 256 | + ans += pq.dequeue(); |
| 257 | + } |
| 258 | + return ans; |
| 259 | +} |
| 260 | +``` |
| 261 | + |
| 262 | +#### Rust |
| 263 | + |
| 264 | +```rust |
| 265 | +use std::cmp::Reverse; |
| 266 | +use std::collections::BinaryHeap; |
| 267 | + |
| 268 | +impl Solution { |
| 269 | + pub fn max_sum(nums: Vec<i32>, threshold: Vec<i32>) -> i64 { |
| 270 | + let n = nums.len(); |
| 271 | + let mut idx: Vec<usize> = (0..n).collect(); |
| 272 | + idx.sort_by_key(|&i| threshold[i]); |
| 273 | + |
| 274 | + let mut pq = BinaryHeap::new(); |
| 275 | + let mut ans: i64 = 0; |
| 276 | + let mut i = 0; |
| 277 | + let mut step = 1; |
| 278 | + |
| 279 | + loop { |
| 280 | + while i < n && threshold[idx[i]] <= step { |
| 281 | + pq.push(nums[idx[i]]); |
| 282 | + i += 1; |
| 283 | + } |
| 284 | + match pq.pop() { |
| 285 | + Some(x) => { |
| 286 | + ans += x as i64; |
| 287 | + step += 1; |
| 288 | + } |
| 289 | + None => break, |
| 290 | + } |
| 291 | + } |
| 292 | + |
| 293 | + ans |
| 294 | + } |
| 295 | +} |
| 296 | +``` |
| 297 | + |
| 298 | +<!-- tabs:end --> |
| 299 | + |
| 300 | +<!-- solution:end --> |
| 301 | + |
| 302 | +<!-- problem:end --> |
0 commit comments