跳转至

3466. 最大硬币收集量 🔒

题目描述

马里奥在双车道高速公路上行驶,每英里都有硬币。给定两个整数数组,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;
}

评论