
题目描述
马里奥在双车道高速公路上行驶,每英里都有硬币。给定两个整数数组,lane1
和 lane2
,其中第 i
个下标的值表示他在车道上处于第 i
英里时获得或失去的硬币数量。
- 如果马里奥在车道 1 上处于
i
英里处,并且 lane1[i] > 0
,马里奥获得 lane1[i]
硬币。
- 如果马里奥在车道 1 上处于
i
英里处,并且 lane1[i] < 0
,马里奥支付通行费并失去 abs(lane1[i])
个硬币。
- 规则同样对
lane2
适用。
马里奥可以在任何地方进入高速公路,并在行驶 至少 一英里后随时退出。马里奥总是从 1 号车道进入高速公路,但 最多 可以换道 2 次。
换道 是指马里奥从车道 1 换到车道 2,反之亦然。
返回马里奥在进行 最多 2 次换道 后 最多 可以获得的硬币数。
注意:马里奥可以在进入高速公路或退出高速公路之前立即切换车道。
示例 1:
输入:lane1 = [1,-2,-10,3], lane2 = [-5,10,0,1]
输出:14
解释:
- 马里奥在车道 1 上行驶了第 1 英里。
- 接着,他切换到车道 2 并继续行驶 2 英里。
- 最后 1 英里他切换回了车道 1。
马里奥收集了 1 + 10 + 0 + 3 = 14
硬币。
示例 2:
输入:lane1 = [1,-1,-1,-1], lane2 = [0,3,4,-5]
输出:8
解释:
- 马里奥从 0 英里处进入车道 1 并行驶了 1 英里。
- 接着,他切换到车道 2 并继续行驶了 2 英里。他在 3 英里处离开高速公路。
他总共收集了 1 + 3 + 4 = 8
硬币。
示例 3:
输入:lane1 = [-5,-4,-3], lane2 = [-1,2,3]
输出:5
解释:
- 马里奥从 1 英里处进入并立即切换到车道 2。他全程保持在这根车道上。
他总共收集了 2 + 3 = 5
硬币。
示例 4:
输入:lane1 = [-3,-3,-3], lane2 = [9,-2,4]
输出:11
解释:
- 马里奥从高速公路的开头进入并立即切换到车道 2。他全程保持在这根车道上。
他总共获得了 9 + (-2) + 4 = 11
硬币。
示例 5:
输入:lane1 = [-10], lane2 = [-2]
输出:-2
解释:
- 由于马里奥必须在高速公路上行驶至少 1 英里,他只在车道 2 上行驶了 1 英里。
他总共获得了 -2 硬币。
提示:
1 <= lane1.length == lane2.length <= 105
-109 <= lane1[i], lane2[i] <= 109
解法
方法一:记忆化搜索
我们设计一个函数 \(\textit{dfs}(i, j, k)\),表示 Mario 从第 \(i\) 个位置开始,当前在第 \(j\) 条车道上,还可以换道 \(k\) 次的情况下,最多可以获得的硬币数。那么答案就是对于所有的 \(i\),取 \(\textit{dfs}(i, 0, 2)\) 的最大值。
函数 \(\textit{dfs}(i, j, k)\) 的计算方式如下:
- 如果 \(i \geq n\),表示已经走到了终点,返回 0;
- 如果不变道,当前可以行驶 1 英里,然后驶出,或者继续行驶,取两者中的最大值,即 \(\max(x, \textit{dfs}(i + 1, j, k) + x)\);
- 如果可以变道,有两种选择,一种是行驶 1 英里,然后变道,另一种是直接变道,取这两种情况的最大值,即 \(\max(\textit{dfs}(i + 1, j \oplus 1, k - 1) + x, \textit{dfs}(i, j \oplus 1, k - 1))\)。
- 其中 \(x\) 表示当前位置的硬币数。
为了避免重复计算,我们使用记忆化搜索的方法,将已经计算过的结果保存下来。
时间复杂度 \(O(n)\),空间复杂度 \(O(n)\)。其中 \(n\) 表示车道的长度。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 | class Solution:
def maxCoins(self, lane1: List[int], lane2: List[int]) -> int:
@cache
def dfs(i: int, j: int, k: int) -> int:
if i >= n:
return 0
x = lane1[i] if j == 0 else lane2[i]
ans = max(x, dfs(i + 1, j, k) + x)
if k > 0:
ans = max(ans, dfs(i + 1, j ^ 1, k - 1) + x)
ans = max(ans, dfs(i, j ^ 1, k - 1))
return ans
n = len(lane1)
ans = -inf
for i in range(n):
ans = max(ans, dfs(i, 0, 2))
return ans
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 | class Solution {
private int n;
private int[] lane1;
private int[] lane2;
private Long[][][] f;
public long maxCoins(int[] lane1, int[] lane2) {
n = lane1.length;
this.lane1 = lane1;
this.lane2 = lane2;
f = new Long[n][2][3];
long ans = Long.MIN_VALUE;
for (int i = 0; i < n; ++i) {
ans = Math.max(ans, dfs(i, 0, 2));
}
return ans;
}
private long dfs(int i, int j, int k) {
if (i >= n) {
return 0;
}
if (f[i][j][k] != null) {
return f[i][j][k];
}
int x = j == 0 ? lane1[i] : lane2[i];
long ans = Math.max(x, dfs(i + 1, j, k) + x);
if (k > 0) {
ans = Math.max(ans, dfs(i + 1, j ^ 1, k - 1) + x);
ans = Math.max(ans, dfs(i, j ^ 1, k - 1));
}
return f[i][j][k] = ans;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 | class Solution {
public:
long long maxCoins(vector<int>& lane1, vector<int>& lane2) {
int n = lane1.size();
long long ans = -1e18;
vector<vector<vector<long long>>> f(n, vector<vector<long long>>(2, vector<long long>(3, -1e18)));
auto dfs = [&](this auto&& dfs, int i, int j, int k) -> long long {
if (i >= n) {
return 0LL;
}
if (f[i][j][k] != -1e18) {
return f[i][j][k];
}
int x = j == 0 ? lane1[i] : lane2[i];
long long ans = max((long long) x, dfs(i + 1, j, k) + x);
if (k > 0) {
ans = max(ans, dfs(i + 1, j ^ 1, k - 1) + x);
ans = max(ans, dfs(i, j ^ 1, k - 1));
}
return f[i][j][k] = ans;
};
for (int i = 0; i < n; ++i) {
ans = max(ans, dfs(i, 0, 2));
}
return ans;
}
};
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 | func maxCoins(lane1 []int, lane2 []int) int64 {
n := len(lane1)
f := make([][2][3]int64, n)
for i := range f {
for j := range f[i] {
for k := range f[i][j] {
f[i][j][k] = -1
}
}
}
var dfs func(int, int, int) int64
dfs = func(i, j, k int) int64 {
if i >= n {
return 0
}
if f[i][j][k] != -1 {
return f[i][j][k]
}
x := int64(lane1[i])
if j == 1 {
x = int64(lane2[i])
}
ans := max(x, dfs(i+1, j, k)+x)
if k > 0 {
ans = max(ans, dfs(i+1, j^1, k-1)+x)
ans = max(ans, dfs(i, j^1, k-1))
}
f[i][j][k] = ans
return ans
}
ans := int64(-1e18)
for i := range lane1 {
ans = max(ans, dfs(i, 0, 2))
}
return ans
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28 | function maxCoins(lane1: number[], lane2: number[]): number {
const n = lane1.length;
const NEG_INF = -1e18;
const f: number[][][] = Array.from({ length: n }, () =>
Array.from({ length: 2 }, () => Array(3).fill(NEG_INF)),
);
const dfs = (dfs: Function, i: number, j: number, k: number): number => {
if (i >= n) {
return 0;
}
if (f[i][j][k] !== NEG_INF) {
return f[i][j][k];
}
const x = j === 0 ? lane1[i] : lane2[i];
let ans = Math.max(x, dfs(dfs, i + 1, j, k) + x);
if (k > 0) {
ans = Math.max(ans, dfs(dfs, i + 1, j ^ 1, k - 1) + x);
ans = Math.max(ans, dfs(dfs, i, j ^ 1, k - 1));
}
f[i][j][k] = ans;
return ans;
};
let ans = NEG_INF;
for (let i = 0; i < n; ++i) {
ans = Math.max(ans, dfs(dfs, i, 0, 2));
}
return ans;
}
|