Facebook Pixel

3259. Maximum Energy Boost From Two Drinks


Problem Description

You are given two integer arrays energyDrinkA and energyDrinkB, each of length n, representing the energy boosts per hour provided by two different energy drinks, A and B, respectively. To maximize your total energy boost, you can drink one energy drink per hour. However, switching from one energy drink to the other requires waiting for one hour to cleanse your system, during which you won't receive any energy boost. You can start with either of the two energy drinks. Return the maximum total energy boost achievable in the next n hours.

Intuition

To solve this problem, we use a dynamic programming approach. We define f[i][0] as the maximum energy boost obtained up to hour i when drinking energy drink A at that hour, and f[i][1] as the maximum energy boost obtained up to hour i when drinking energy drink B at that hour.

The key challenge is to balance between the energy boost obtained by consistently drinking the same energy drink and the potential benefit of switching drinks, despite the one-hour penalty.

We initialize:

  • f[0][0] with the energy boost from energyDrinkA[0].
  • f[0][1] with the energy boost from energyDrinkB[0].

The state transitions are defined as follows for each hour i from 1 to n-1:

  • f[i][0] is the maximum of continuing with drink A (f[i-1][0] + energyDrinkA[i]) or switching from drink B (f[i-1][1] because of the penalty hour).
  • f[i][1] is the maximum of continuing with drink B (f[i-1][1] + energyDrinkB[i]) or switching from drink A (f[i-1][0]).

Finally, the result is the maximum value between f[n-1][0] and f[n-1][1], representing the best possible total energy boost achievable by the end of the n hours.

Learn more about Dynamic Programming patterns.

Solution Approach

The solution is implemented using a dynamic programming approach. We utilize a 2D list f to keep track of the maximum energy boost achievable up to each hour i, with separate entries for choosing energy drink A or B at that hour.

  1. Initialization:

    • Create a 2D list f with n rows and 2 columns, each initialized to 0. This will store the maximum energy boost for each hour i using either drink A or drink B.
    • Set f[0][0] to energyDrinkA[0], representing the initial choice of drink A.
    • Set f[0][1] to energyDrinkB[0], representing the initial choice of drink B.
  2. State Transitions:

    • For each hour i from 1 to n-1, compute:
      • f[i][0] as max(f[i - 1][0] + energyDrinkA[i], f[i - 1][1]): the maximum energy boost by either continuing with drink A from the previous hour or switching from drink B after a one-hour wait.
      • f[i][1] as max(f[i - 1][1] + energyDrinkB[i], f[i - 1][0]): similarly, the maximum energy boost by either continuing with drink B from the previous hour or switching from drink A after a one-hour wait.
  3. Result:

    • Return max(f[n - 1][0], f[n - 1][1]) to retrieve the highest energy boost possible by the end of n hours.

Here's the code implementing the approach:

class Solution:
    def maxEnergyBoost(self, energyDrinkA: List[int], energyDrinkB: List[int]) -> int:
        n = len(energyDrinkA)
        f = [[0] * 2 for _ in range(n)]
        f[0][0] = energyDrinkA[0]
        f[0][1] = energyDrinkB[0]
        for i in range(1, n):
            f[i][0] = max(f[i - 1][0] + energyDrinkA[i], f[i - 1][1])
            f[i][1] = max(f[i - 1][1] + energyDrinkB[i], f[i - 1][0])
        return max(f[n - 1])

This algorithm efficiently computes the maximum possible energy boost by dynamically deciding whether to switch drinks or continue with the current choice, considering the penalty for switching.

Ready to land your dream job?

Unlock your dream job with a 2-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through the solution approach using a small example. Assume energyDrinkA = [3, 2, 7] and energyDrinkB = [4, 5, 1].

  1. Initialization:

    • Length of the arrays, n = 3.
    • Create a 2D list f with dimensions 3 x 2. Initially, f is [[0, 0], [0, 0], [0, 0]].
    • Set the base cases:
      • f[0][0] = energyDrinkA[0] = 3
      • f[0][1] = energyDrinkB[0] = 4
      • So, f is now [[3, 4], [0, 0], [0, 0]].
  2. State Transitions:

    • For hour 1 (i = 1):
      • f[1][0] = max(f[0][0] + energyDrinkA[1], f[0][1]) = max(3 + 2, 4) = max(5, 4) = 5
      • f[1][1] = max(f[0][1] + energyDrinkB[1], f[0][0]) = max(4 + 5, 3) = max(9, 3) = 9
      • f becomes [[3, 4], [5, 9], [0, 0]].
    • For hour 2 (i = 2):
      • f[2][0] = max(f[1][0] + energyDrinkA[2], f[1][1]) = max(5 + 7, 9) = max(12, 9) = 12
      • f[2][1] = max(f[1][1] + energyDrinkB[2], f[1][0]) = max(9 + 1, 5) = max(10, 5) = 10
      • f updates to [[3, 4], [5, 9], [12, 10]].
  3. Result:

    • The maximum total energy boost achievable in the next 3 hours is max(f[2][0], f[2][1]) = max(12, 10) = 12.

Therefore, the maximum energy boost achievable is 12 units.

Solution Implementation

1from typing import List
2
3class Solution:
4    def maxEnergyBoost(self, energyDrinkA: List[int], energyDrinkB: List[int]) -> int:
5        n = len(energyDrinkA)  # Get the number of days or drinks
6        # Initialize a 2D list to store maximum energy potential for each day and each option (A or B)
7        f = [[0] * 2 for _ in range(n)]
8      
9        # Base cases for the first day
10        f[0][0] = energyDrinkA[0]  # Energy boost if drink A is chosen on the first day
11        f[0][1] = energyDrinkB[0]  # Energy boost if drink B is chosen on the first day
12      
13        # Iterate through each day starting from the second day
14        for i in range(1, n):
15            # Maximum energy if drink A is chosen on the ith day
16            f[i][0] = max(f[i - 1][0] + energyDrinkA[i], f[i - 1][1])
17            # Maximum energy if drink B is chosen on the ith day
18            f[i][1] = max(f[i - 1][1] + energyDrinkB[i], f[i - 1][0])
19      
20        # Return the maximum energy boost possible on the last day from either drink A or B
21        return max(f[n - 1])
22
1class Solution {
2    public long maxEnergyBoost(int[] energyDrinkA, int[] energyDrinkB) {
3        // Get the number of drinks
4        int n = energyDrinkA.length;
5      
6        // Initialize a 2D array to store maximum energy collected up to each drink
7        long[][] maxEnergy = new long[n][2];
8      
9        // Base case: the first drink's energy is directly taken for both types
10        maxEnergy[0][0] = energyDrinkA[0];
11        maxEnergy[0][1] = energyDrinkB[0];
12      
13        // Dynamic programming to fill up the maxEnergy array
14        for (int i = 1; i < n; ++i) {
15            // For drink type A: 
16            // 1. Add current energy drink A to the previous max for type A
17            // 2. Choose the previous best result from type B
18            maxEnergy[i][0] = Math.max(maxEnergy[i - 1][0] + energyDrinkA[i], maxEnergy[i - 1][1]);
19          
20            // For drink type B:
21            // 1. Add current energy drink B to the previous max for type B
22            // 2. Choose the previous best result from type A
23            maxEnergy[i][1] = Math.max(maxEnergy[i - 1][1] + energyDrinkB[i], maxEnergy[i - 1][0]);
24        }
25      
26        // Return the maximum energy collected considering both sequences
27        return Math.max(maxEnergy[n - 1][0], maxEnergy[n - 1][1]);
28    }
29}
30
1class Solution {
2public:
3    long long maxEnergyBoost(vector<int>& energyDrinkA, vector<int>& energyDrinkB) {
4        int n = energyDrinkA.size();  // Determine the number of energy drinks
5        vector<vector<long long>> dp(n, vector<long long>(2));
6      
7        // Initialize the first day's potential boost from each drink
8        dp[0][0] = energyDrinkA[0];
9        dp[0][1] = energyDrinkB[0];
10      
11        // Iterate through each day, calculating the maximum energy boost
12        for (int i = 1; i < n; ++i) {
13            // Calculate the maximum boost if drinking from energyDrinkA on day i
14            dp[i][0] = max(dp[i - 1][0] + energyDrinkA[i], dp[i - 1][1]);
15          
16            // Calculate the maximum boost if drinking from energyDrinkB on day i
17            dp[i][1] = max(dp[i - 1][1] + energyDrinkB[i], dp[i - 1][0]);
18        }
19      
20        // Return the maximum boost possible on the last day from either drink
21        return max(dp[n - 1][0], dp[n - 1][1]);
22    }
23};
24
1function maxEnergyBoost(energyDrinkA: number[], energyDrinkB: number[]): number {
2    // Number of energy drinks
3    const n = energyDrinkA.length;
4
5    // Create a 2D array to store the maximum energy boost achievable at each step
6    // f[i][0] represents the max energy boost if using drink A at step i
7    // f[i][1] represents the max energy boost if using drink B at step i
8    const f: number[][] = Array.from({ length: n }, () => [0, 0]);
9
10    // Initialize the first step with the initial energy from drink A and drink B
11    f[0][0] = energyDrinkA[0];
12    f[0][1] = energyDrinkB[0];
13
14    // Iterate through each energy drink starting from the second one
15    for (let i = 1; i < n; i++) {
16        // Calculate the max energy boost when choosing drink A at step i
17        // Option 1: Continue using drink A from the previous step
18        // Option 2: Switch to drink A after using drink B in the previous step
19        f[i][0] = Math.max(f[i - 1][0] + energyDrinkA[i], f[i - 1][1]);
20
21        // Calculate the max energy boost when choosing drink B at step i
22        // Option 1: Continue using drink B from the previous step
23        // Option 2: Switch to drink B after using drink A in the previous step
24        f[i][1] = Math.max(f[i - 1][1] + energyDrinkB[i], f[i - 1][0]);
25    }
26
27    // Return the maximum energy boost obtainable after using all drinks
28    return Math.max(f[n - 1][0], f[n - 1][1]);
29}
30

Time and Space Complexity

The time complexity of the code is O(n) because it involves a single loop that iterates through the list from start to finish, where n is the length of the input arrays energyDrinkA and energyDrinkB. Each iteration involves constant-time operations.

The space complexity of the code is O(n) due to the 2D list f created to store intermediate results. This list requires space proportional to n, with two entries per element to track the maximum energy boost for selecting either energyDrinkA[i] or energyDrinkB[i] at each step.

Learn more about how to find time and space complexity quickly.


Discover Your Strengths and Weaknesses: Take Our 2-Minute Quiz to Tailor Your Study Plan:
Question 1 out of 10

Which of the following uses divide and conquer strategy?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!


Load More