力扣每日一题 超级饮料的最大强化能量 动态规划(dp)
来自未来的体育科学家给你两个整数数组 energyDrinkA 和 energyDrinkB,数组长度都等于 n。这两个数组分别代表 A、B 两种不同能量饮料每小时所能提供的强化能量。
你需要每小时饮用一种能量饮料来 最大化 你的总强化能量。然而,如果从一种能量饮料切换到另一种,你需要等待一小时来梳理身体的能量体系(在那个小时里你将不会获得任何强化能量)。
返回在接下来的 n 小时内你能获得的 最大 总强化能量。
注意 你可以选择从饮用任意一种能量饮料开始。
示例 1: 输入:energyDrinkA = [1,3,1], energyDrinkB = [3,1,1] 输出:5
解释: 要想获得 5 点强化能量,需要选择只饮用能量饮料 A(或者只饮用 B)。
示例 2: 输入:energyDrinkA = [4,1,1], energyDrinkB = [1,1,3] 输出:7
解释:
• 第一个小时饮用能量饮料 A。
• 切换到能量饮料 B ,在第二个小时无法获得强化能量。
• 第三个小时饮用能量饮料 B ,并获得强化能量。
思路
这题题目描述有点不明确,概括一下题意就是有有两个饮料序列,分别代表饮料在1-n小时的能量值,开始时可以选择任意一种饮料饮用,每个小时只能选择一瓶饮料引用,如果你刚开始选的是第一种饮料,后面想要喝第二种饮料的话就需要等待一小时,即下一个小时无法饮用任何饮料,求第n小时过后能获得多少能量
题目中提到了如果要切换饮料种类就需要空等一小时,如果按照贪心的策略想的话这肯定是不合理的,所以这题不能用贪心解,所以当我们决定切换饮料,一定是我们可以获得更大收益的,这两天正好在学习dp,一瞬间就想到改用dp来解
设置数组
long[][] dp=new long[n+1][2];
dp[i][0]代表第i时刻选择饮料A所能获得的最大能量
dp[i][1]代表第i时刻选择饮料B所能获得的最大能量
假设当前选择能量A又有两种两种可能
1.前一次选择的也是能量A 即 dp[i][0]= dp[i-1][0] + energyDrinkA[i]
2.前一次选的是能量B 则 dp[i][0]= dp[i-2][1] + energyDrinkA[i];
两者之中取较大值,可得
dp[i][0]=Math.max(dp[i-1][0],dp[i-2][1])+energyDrinkA[i];
同理,饮料B的递推公式 dp[i][1]=Math.max( dp[i-1][1] , dp[i-2][0] ) + energyDrinkB[i];
初始化
dp[0][0]=energyDrinkA[0];
dp[0][1]=energyDrinkB[0];
dp[1][0]=dp[0][0]+energyDrinkA[1];
dp[1][1]=dp[0][1]+energyDrinkB[1];
下标为0的就是第一次喝饮料,直接取第一个饮料的能量即可
对于第二次选择,由于饮料的种类转移需要花费一个小时的时间,而前两次仅仅只有两个小时的时间,转移饮料种类无法获得任何能量,只会浪费第二个小时的时间,所以前两次都喝相同的饮料
完整代码
class Solution {
public long maxEnergyBoost(int[] energyDrinkA, int[] energyDrinkB) {
int n=energyDrinkA.length;
long[][] dp=new long[n+1][2];
dp[0][0]=energyDrinkA[0];
dp[0][1]=energyDrinkB[0];
dp[1][0]=dp[0][0]+energyDrinkA[1];
dp[1][1]=dp[0][1]+energyDrinkB[1];
for(int i=2;i<n;i++){
dp[i][0]=Math.max(dp[i-1][0],dp[i-2][1])+energyDrinkA[i];
dp[i][1]=Math.max(dp[i-1][1],dp[i-2][0])+energyDrinkB[i];
}
return Math.max(dp[n-1][0],dp[n-1][1]);
}
}