Every day a Leetcode
题目来源:3259. 超级饮料的最大强化能量
解法1:记忆化搜索
本题的状态定义 dfs(i,j)。其中 j=0,1,分别表示最后选的是 energyDrinkA[i] 还是 energyDrinkB[i]。
为方便实现,把 energyDrinkA 和 energyDrinkB 加到一个长为 2 的二维数组 c 中。
分类讨论:
-
继续选 c[j] 中的元素,那么下一个数选 c[j][i−1],需要解决的问题为:从下标 [0,i−1] 中选数字,且最后选的是 c[j] 中的元素的情况下,所选元素之和的最大值,即 dfs(i−1,j)。
-
改成选 c[j⊕1] 中的元素,那么下一个数选 c[j⊕1][i−2],需要解决的问题为:从下标 [0,i−2] 中选数字,且最后选的是 c[j⊕1] 中的元素的情况下,所选元素之和的最大值,即 dfs(i−2,j⊕1)。其中 ⊕ 为异或运算,通过异或 1,可以把 0 变成 1,把 1 变成 0。
代码:
#
# @lc app=leetcode.cn id=3259 lang=python3
#
# [3259] 超级饮料的最大强化能量
#
# @lc code=start
class Solution:
def maxEnergyBoost(self, energyDrinkA: List[int], energyDrinkB: List[int]) -> int:
n = len(energyDrinkA)
energyDrink = (energyDrinkA, energyDrinkB)
@cache # 缓存装饰器,避免重复计算 dfs 的结果(记忆化)
def dfs(i: int, j: int) -> int:
if i < 0:
return 0
res1 = dfs(i - 1, j) + energyDrink[j][i]
res2 = dfs(i - 2, j ^ 1) + energyDrink[j][i]
return max(res1, res2)
return max(dfs(n - 1, 0), dfs(n - 1, 1))
# @lc code=end
结果:
复杂度分析:
时间复杂度:O(n),其中 n 为数组 energyDrinkA/energyDrinkB 的长度。由于每个状态只会计算一次,动态规划的时间复杂度 = 状态个数 × 单个状态的计算时间。本题状态个数等于 O(n),单个状态的计算时间为 O(1),所以总的时间复杂度为 O(n)。
空间复杂度:O(n),其中 n 为数组 energyDrinkA/energyDrinkB 的长度。保存多少状态,就需要多少空间。
解法2:动态规划
代码:
/*
* @lc app=leetcode.cn id=3259 lang=cpp
*
* [3259] 超级饮料的最大强化能量
*/
// @lc code=start
class Solution
{
public:
long long maxEnergyBoost(vector<int> &energyDrinkA, vector<int> &energyDrinkB)
{
int n = energyDrinkA.size();
vector<array<long long, 2>> dp(n + 2);
// 状态转移
for (int i = 0; i < n; i++)
{
dp[i + 2][0] = max(dp[i + 1][0], dp[i][1]) + energyDrinkA[i];
dp[i + 2][1] = max(dp[i + 1][1], dp[i][0]) + energyDrinkB[i];
}
return max(dp[n + 1][0], dp[n + 1][1]);
}
};
// @lc code=end
结果:
复杂度分析:
时间复杂度:O(n),其中 n 为数组 energyDrinkA/energyDrinkB 的长度。
空间复杂度:O(n),其中 n 为数组 energyDrinkA/energyDrinkB 的长度。