Skip to content

Commit ecd524b

Browse files
authored
feat: add solutions to lc problems: No.3180,3181 (#3094)
* No.3180.Maximum Total Reward Using Operations I * No.3181.Maximum Total Reward Using Operations II
1 parent d6e496a commit ecd524b

File tree

17 files changed

+816
-10
lines changed

17 files changed

+816
-10
lines changed

solution/3100-3199/3180.Maximum Total Reward Using Operations I/README.md

+236
Original file line numberDiff line numberDiff line change
@@ -222,4 +222,240 @@ function maxTotalReward(rewardValues: number[]): number {
222222

223223
<!-- solution:end -->
224224

225+
<!-- solution:start -->
226+
227+
### 方法二:动态规划
228+
229+
我们定义 $f[i][j]$ 表示用前 $i$ 个奖励值,能否得到总奖励 $j$。初始时 $f[0][0] = \text{True}$,其余值均为 $\text{False}$。
230+
231+
我们考虑第 $i$ 个奖励值 $v$,如果我们不选择它,那么 $f[i][j] = f[i - 1][j]$;如果我们选择它,那么 $f[i][j] = f[i - 1][j - v]$,其中 $0 \leq j - v \lt v$。即状态转移方程为:
232+
233+
$$
234+
f[i][j] = f[i - 1][j] \vee f[i - 1][j - v]
235+
$$
236+
237+
最终答案为 $\max\{j \mid f[n][j] = \text{True}\}$。
238+
239+
由于 $f[i][j]$ 只与 $f[i - 1][j]$ 和 $f[i - 1][j - v]$ 有关,我们可以优化掉第一维,只使用一个一维数组进行状态转移。
240+
241+
时间复杂度 $O(n \times M)$,空间复杂度 $O(M)$。其中 $n$ 是数组 `rewardValues` 的长度,而 $M$ 是数组 `rewardValues` 中的最大值的两倍。
242+
243+
<!-- tabs:start -->
244+
245+
#### Python3
246+
247+
```python
248+
class Solution:
249+
def maxTotalReward(self, rewardValues: List[int]) -> int:
250+
nums = sorted(set(rewardValues))
251+
m = nums[-1] << 1
252+
f = [False] * m
253+
f[0] = True
254+
for v in nums:
255+
for j in range(m):
256+
if 0 <= j - v < v:
257+
f[j] |= f[j - v]
258+
ans = m - 1
259+
while not f[ans]:
260+
ans -= 1
261+
return ans
262+
```
263+
264+
#### Java
265+
266+
```java
267+
class Solution {
268+
public int maxTotalReward(int[] rewardValues) {
269+
int[] nums = Arrays.stream(rewardValues).distinct().sorted().toArray();
270+
int n = nums.length;
271+
int m = nums[n - 1] << 1;
272+
boolean[] f = new boolean[m];
273+
f[0] = true;
274+
for (int v : nums) {
275+
for (int j = 0; j < m; ++j) {
276+
if (0 <= j - v && j - v < v) {
277+
f[j] |= f[j - v];
278+
}
279+
}
280+
}
281+
int ans = m - 1;
282+
while (!f[ans]) {
283+
--ans;
284+
}
285+
return ans;
286+
}
287+
}
288+
```
289+
290+
#### C++
291+
292+
```cpp
293+
class Solution {
294+
public:
295+
int maxTotalReward(vector<int>& rewardValues) {
296+
sort(rewardValues.begin(), rewardValues.end());
297+
rewardValues.erase(unique(rewardValues.begin(), rewardValues.end()), rewardValues.end());
298+
int n = rewardValues.size();
299+
int m = rewardValues.back() << 1;
300+
bool f[m];
301+
memset(f, false, sizeof(f));
302+
f[0] = true;
303+
for (int v : rewardValues) {
304+
for (int j = 1; j < m; ++j) {
305+
if (0 <= j - v && j - v < v) {
306+
f[j] = f[j] || f[j - v];
307+
}
308+
}
309+
}
310+
int ans = m - 1;
311+
while (!f[ans]) {
312+
--ans;
313+
}
314+
return ans;
315+
}
316+
};
317+
```
318+
319+
#### Go
320+
321+
```go
322+
func maxTotalReward(rewardValues []int) int {
323+
slices.Sort(rewardValues)
324+
nums := slices.Compact(rewardValues)
325+
n := len(nums)
326+
m := nums[n-1] << 1
327+
f := make([]bool, m)
328+
f[0] = true
329+
for _, v := range nums {
330+
for j := 1; j < m; j++ {
331+
if 0 <= j-v && j-v < v {
332+
f[j] = f[j] || f[j-v]
333+
}
334+
}
335+
}
336+
ans := m - 1
337+
for !f[ans] {
338+
ans--
339+
}
340+
return ans
341+
}
342+
```
343+
344+
#### TypeScript
345+
346+
```ts
347+
function maxTotalReward(rewardValues: number[]): number {
348+
const nums = Array.from(new Set(rewardValues)).sort((a, b) => a - b);
349+
const n = nums.length;
350+
const m = nums[n - 1] << 1;
351+
const f: boolean[] = Array(m).fill(false);
352+
f[0] = true;
353+
for (const v of nums) {
354+
for (let j = 1; j < m; ++j) {
355+
if (0 <= j - v && j - v < v) {
356+
f[j] = f[j] || f[j - v];
357+
}
358+
}
359+
}
360+
let ans = m - 1;
361+
while (!f[ans]) {
362+
--ans;
363+
}
364+
return ans;
365+
}
366+
```
367+
368+
<!-- tabs:end -->
369+
370+
<!-- solution:end -->
371+
372+
<!-- solution:start -->
373+
374+
### 方法三:动态规划 + 位运算
375+
376+
我们可以对方法二进行优化,定义一个二进制数 $f$ 保存当前的状态,其中 $f$ 的第 $i$ 位为 $1$ 表示当前总奖励为 $i$ 是可达的。
377+
378+
观察方法二的状态转移方程 $f[j] = f[j] \vee f[j - v]$,这相当于取 $f$ 的低 $v$ 位,再左移 $v$ 位,然后与原来的 $f$ 进行或运算。
379+
380+
那么答案为 $f$ 的最高位的位置。
381+
382+
时间复杂度 $O(n \times M / w)$,空间复杂度 $O(n + M / w)$。其中 $n$ 是数组 `rewardValues` 的长度,而 $M$ 是数组 `rewardValues` 中的最大值的两倍。整数 $w = 32$ 或 $64$。
383+
384+
<!-- tabs:start -->
385+
386+
#### Python3
387+
388+
```python
389+
class Solution:
390+
def maxTotalReward(self, rewardValues: List[int]) -> int:
391+
nums = sorted(set(rewardValues))
392+
f = 1
393+
for v in nums:
394+
f |= (f & ((1 << v) - 1)) << v
395+
return f.bit_length() - 1
396+
```
397+
398+
#### Java
399+
400+
```java
401+
import java.math.BigInteger;
402+
import java.util.Arrays;
403+
404+
class Solution {
405+
public int maxTotalReward(int[] rewardValues) {
406+
int[] nums = Arrays.stream(rewardValues).distinct().sorted().toArray();
407+
BigInteger f = BigInteger.ONE;
408+
for (int v : nums) {
409+
BigInteger mask = BigInteger.ONE.shiftLeft(v).subtract(BigInteger.ONE);
410+
BigInteger shifted = f.and(mask).shiftLeft(v);
411+
f = f.or(shifted);
412+
}
413+
return f.bitLength() - 1;
414+
}
415+
}
416+
```
417+
418+
#### C++
419+
420+
```cpp
421+
class Solution {
422+
public:
423+
int maxTotalReward(vector<int>& rewardValues) {
424+
sort(rewardValues.begin(), rewardValues.end());
425+
rewardValues.erase(unique(rewardValues.begin(), rewardValues.end()), rewardValues.end());
426+
bitset<100000> f{1};
427+
for (int v : rewardValues) {
428+
int shift = f.size() - v;
429+
f |= f << shift >> (shift - v);
430+
}
431+
for (int i = rewardValues.back() * 2 - 1;; i--) {
432+
if (f.test(i)) {
433+
return i;
434+
}
435+
}
436+
}
437+
};
438+
```
439+
440+
#### Go
441+
442+
```go
443+
func maxTotalReward(rewardValues []int) int {
444+
slices.Sort(rewardValues)
445+
rewardValues = slices.Compact(rewardValues)
446+
one := big.NewInt(1)
447+
f := big.NewInt(1)
448+
p := new(big.Int)
449+
for _, v := range rewardValues {
450+
mask := p.Sub(p.Lsh(one, uint(v)), one)
451+
f.Or(f, p.Lsh(p.And(f, mask), uint(v)))
452+
}
453+
return f.BitLen() - 1
454+
}
455+
```
456+
457+
<!-- tabs:end -->
458+
459+
<!-- solution:end -->
460+
225461
<!-- problem:end -->

0 commit comments

Comments
 (0)