Facebook Pixel

2383. Minimum Hours of Training to Win a Competition

Problem Description

You're entering a competition where you must defeat n opponents in order. You start with initialEnergy and initialExperience.

Each opponent i has:

  • energy[i]: their energy level
  • experience[i]: their experience level

Rules for defeating opponents:

  • To defeat opponent i, you must have strictly greater energy AND experience than them (your energy > energy[i] AND your experience > experience[i])
  • After defeating opponent i:
    • Your energy decreases by energy[i]
    • Your experience increases by experience[i]

Training before the competition:

  • You can train for some number of hours before starting
  • Each hour of training lets you choose ONE of:
    • Increase your initial energy by 1, OR
    • Increase your initial experience by 1

Goal: Find the minimum number of training hours needed to defeat all n opponents in order.

Example walkthrough: If you have 5 energy and 3 experience, and face an opponent with 4 energy and 4 experience:

  • You need energy > 4, so your 5 energy is sufficient
  • You need experience > 4, but you only have 3
  • You must train for at least 2 hours to increase experience to 5
  • After defeating this opponent: your energy becomes 5 - 4 = 1, and your experience becomes 5 + 4 = 9

The solution simulates the competition, calculating the minimum training needed before each opponent to ensure you can defeat them, while tracking how your stats change after each victory.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The key insight is that we can use a greedy approach - we only need to train exactly when we're about to face an opponent we can't defeat with our current stats.

Think about it this way: since we face opponents in a fixed order, we can simulate the entire competition step by step. At each opponent, we ask: "Can I defeat them with my current energy and experience?"

If not, we need to train. But here's the clever part - we don't need to decide upfront how to split our training between energy and experience. Instead, we can make this decision just-in-time for each opponent:

  1. Check energy requirement: If my current energy x is not greater than opponent's energy dx, I need to train until I have dx + 1 energy. This requires dx + 1 - x hours of energy training.

  2. Check experience requirement: Similarly, if my current experience y is not greater than opponent's experience dy, I need dy + 1 - y hours of experience training.

  3. Update stats after victory: Once we ensure we can defeat the opponent, we simulate the battle - subtract dx from our energy and add dy to our experience.

Why does this greedy approach work? Because:

  • Training hours are independent (1 hour = 1 point in either stat)
  • We must defeat opponents in order, so we can't skip ahead
  • Any "extra" training done early doesn't hurt us - if we train more than needed for opponent i, that extra energy/experience might help with opponent i+1
  • We only train the minimum needed at each step, accumulating the total training hours as we go

This simulation approach naturally finds the minimum training hours because we only train when absolutely necessary and only the exact amount needed to proceed.

Learn more about Greedy patterns.

Solution Approach

Let's implement the greedy simulation approach step by step:

Initialize variables:

  • x = current energy (starts as initialEnergy)
  • y = current experience (starts as initialExperience)
  • ans = total training hours needed (starts at 0)

Process each opponent in order:

For each opponent i with energy dx = energy[i] and experience dy = experience[i]:

  1. Check and train for energy if needed:

    if x <= dx:
        ans += dx + 1 - x  # Add training hours needed
        x = dx + 1          # Update energy to minimum required

    If our current energy x is not strictly greater than dx, we need to train. We calculate exactly how many hours needed: dx + 1 - x (to reach dx + 1).

  2. Check and train for experience if needed:

    if y <= dy:
        ans += dy + 1 - y  # Add training hours needed
        y = dy + 1         # Update experience to minimum required

    Same logic applies for experience - if y is not strictly greater than dy, train until we have dy + 1 experience.

  3. Simulate the battle:

    x -= dx  # Lose energy after defeating opponent
    y += dy  # Gain experience after defeating opponent

    After ensuring we can defeat the opponent, update our stats according to the battle outcome.

Using zip for clean iteration: The solution uses zip(energy, experience) to iterate through both arrays simultaneously, getting (dx, dy) pairs for each opponent.

Time Complexity: O(n) where n is the number of opponents - we process each opponent exactly once.

Space Complexity: O(1) - we only use a constant amount of extra space for variables.

The beauty of this approach is its simplicity - we handle each opponent sequentially, training only the minimum amount needed at each step, and the sum of all these minimum training sessions gives us the overall minimum.

Ready to land your dream job?

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

Start Evaluator

Example Walkthrough

Let's walk through a concrete example to see how the greedy simulation works.

Input:

  • initialEnergy = 2, initialExperience = 4
  • energy = [1, 4, 3], experience = [2, 6, 3]

Step-by-step simulation:

Initial state:

  • Current energy: x = 2
  • Current experience: y = 4
  • Training hours: ans = 0

Opponent 1: energy = 1, experience = 2

  • Energy check: x = 2 > 1 βœ“ (no training needed)
  • Experience check: y = 4 > 2 βœ“ (no training needed)
  • Battle: x = 2 - 1 = 1, y = 4 + 2 = 6
  • Total training: ans = 0

Opponent 2: energy = 4, experience = 6

  • Energy check: x = 1 ≀ 4 βœ— (need training!)
    • Need energy > 4, so need at least 5 energy
    • Training hours: 5 - 1 = 4 hours
    • Update: x = 5, ans = 0 + 4 = 4
  • Experience check: y = 6 ≀ 6 βœ— (need training!)
    • Need experience > 6, so need at least 7 experience
    • Training hours: 7 - 6 = 1 hour
    • Update: y = 7, ans = 4 + 1 = 5
  • Battle: x = 5 - 4 = 1, y = 7 + 6 = 13
  • Total training: ans = 5

Opponent 3: energy = 3, experience = 3

  • Energy check: x = 1 ≀ 3 βœ— (need training!)
    • Need energy > 3, so need at least 4 energy
    • Training hours: 4 - 1 = 3 hours
    • Update: x = 4, ans = 5 + 3 = 8
  • Experience check: y = 13 > 3 βœ“ (no training needed)
  • Battle: x = 4 - 3 = 1, y = 13 + 3 = 16
  • Total training: ans = 8

Result: Minimum training hours needed = 8

Notice how we only train exactly when needed and only the minimum amount required. The experience gained from defeating opponents accumulates, which is why we didn't need experience training for the third opponent despite their requirement.

Solution Implementation

1class Solution:
2    def minNumberOfHours(
3        self, initial_energy: int, initial_experience: int, 
4        energy: List[int], experience: List[int]
5    ) -> int:
6        """
7        Calculate minimum training hours needed to defeat all opponents.
8      
9        Args:
10            initial_energy: Starting energy level
11            initial_experience: Starting experience level
12            energy: List of energy values for each opponent
13            experience: List of experience values for each opponent
14          
15        Returns:
16            Minimum number of training hours needed
17        """
18        # Track total training hours needed
19        training_hours = 0
20      
21        # Current energy and experience levels
22        current_energy = initial_energy
23        current_experience = initial_experience
24      
25        # Process each opponent in order
26        for opponent_energy, opponent_experience in zip(energy, experience):
27            # Check if we need to train for more energy
28            # We need strictly more energy than the opponent to win
29            if current_energy <= opponent_energy:
30                # Calculate hours needed to have just enough energy
31                energy_deficit = opponent_energy + 1 - current_energy
32                training_hours += energy_deficit
33                current_energy = opponent_energy + 1
34          
35            # Check if we need to train for more experience
36            # We need strictly more experience than the opponent to win
37            if current_experience <= opponent_experience:
38                # Calculate hours needed to have just enough experience
39                experience_deficit = opponent_experience + 1 - current_experience
40                training_hours += experience_deficit
41                current_experience = opponent_experience + 1
42          
43            # After defeating the opponent:
44            # - Energy decreases by opponent's energy
45            # - Experience increases by opponent's experience
46            current_energy -= opponent_energy
47            current_experience += opponent_experience
48      
49        return training_hours
50
1class Solution {
2    public int minNumberOfHours(int initialEnergy, int initialExperience, int[] energy, int[] experience) {
3        int totalTrainingHours = 0;
4        int currentEnergy = initialEnergy;
5        int currentExperience = initialExperience;
6      
7        // Process each opponent in order
8        for (int i = 0; i < energy.length; i++) {
9            int opponentEnergy = energy[i];
10            int opponentExperience = experience[i];
11          
12            // Check if we need to train for energy
13            // We need strictly more energy than the opponent to defeat them
14            if (currentEnergy <= opponentEnergy) {
15                int energyNeeded = opponentEnergy + 1 - currentEnergy;
16                totalTrainingHours += energyNeeded;
17                currentEnergy = opponentEnergy + 1;
18            }
19          
20            // Check if we need to train for experience
21            // We need strictly more experience than the opponent to defeat them
22            if (currentExperience <= opponentExperience) {
23                int experienceNeeded = opponentExperience + 1 - currentExperience;
24                totalTrainingHours += experienceNeeded;
25                currentExperience = opponentExperience + 1;
26            }
27          
28            // After defeating the opponent:
29            // - Energy decreases by opponent's energy
30            // - Experience increases by opponent's experience
31            currentEnergy -= opponentEnergy;
32            currentExperience += opponentExperience;
33        }
34      
35        return totalTrainingHours;
36    }
37}
38
1class Solution {
2public:
3    int minNumberOfHours(int initialEnergy, int initialExperience, vector<int>& energy, vector<int>& experience) {
4        int trainingHours = 0;
5        int currentEnergy = initialEnergy;
6        int currentExperience = initialExperience;
7      
8        // Process each opponent in order
9        for (int i = 0; i < energy.size(); ++i) {
10            int opponentEnergy = energy[i];
11            int opponentExperience = experience[i];
12          
13            // Check if we need to train to have enough energy to defeat this opponent
14            // We need strictly more energy than the opponent
15            if (currentEnergy <= opponentEnergy) {
16                int energyNeeded = opponentEnergy + 1 - currentEnergy;
17                trainingHours += energyNeeded;
18                currentEnergy = opponentEnergy + 1;
19            }
20          
21            // Check if we need to train to have enough experience to defeat this opponent
22            // We need strictly more experience than the opponent
23            if (currentExperience <= opponentExperience) {
24                int experienceNeeded = opponentExperience + 1 - currentExperience;
25                trainingHours += experienceNeeded;
26                currentExperience = opponentExperience + 1;
27            }
28          
29            // After defeating the opponent:
30            // - Energy decreases by opponent's energy value
31            // - Experience increases by opponent's experience value
32            currentEnergy -= opponentEnergy;
33            currentExperience += opponentExperience;
34        }
35      
36        return trainingHours;
37    }
38};
39
1/**
2 * Calculates the minimum number of training hours needed to defeat all opponents
3 * @param initialEnergy - Starting energy level
4 * @param initialExperience - Starting experience level
5 * @param energy - Array of energy requirements for each opponent
6 * @param experience - Array of experience requirements for each opponent
7 * @returns Minimum number of training hours needed
8 */
9function minNumberOfHours(
10    initialEnergy: number, 
11    initialExperience: number, 
12    energy: number[], 
13    experience: number[]
14): number {
15    let trainingHours = 0;
16    let currentEnergy = initialEnergy;
17    let currentExperience = initialExperience;
18  
19    // Iterate through each opponent
20    for (let i = 0; i < energy.length; i++) {
21        const opponentEnergy = energy[i];
22        const opponentExperience = experience[i];
23      
24        // Check if we need to train to have more energy than opponent
25        if (currentEnergy <= opponentEnergy) {
26            // Calculate hours needed to exceed opponent's energy
27            const energyDeficit = opponentEnergy + 1 - currentEnergy;
28            trainingHours += energyDeficit;
29            currentEnergy = opponentEnergy + 1;
30        }
31      
32        // Check if we need to train to have more experience than opponent
33        if (currentExperience <= opponentExperience) {
34            // Calculate hours needed to exceed opponent's experience
35            const experienceDeficit = opponentExperience + 1 - currentExperience;
36            trainingHours += experienceDeficit;
37            currentExperience = opponentExperience + 1;
38        }
39      
40        // After defeating opponent: lose energy, gain experience
41        currentEnergy -= opponentEnergy;
42        currentExperience += opponentExperience;
43    }
44  
45    return trainingHours;
46}
47

Time and Space Complexity

Time Complexity: O(n), where n is the length of the energy and experience arrays (number of opponents). The algorithm iterates through both arrays exactly once using the zip function, performing constant-time operations for each opponent (comparisons, additions, and subtractions).

Space Complexity: O(1). The algorithm only uses a fixed amount of extra space for variables ans, dx, and dy, regardless of the input size. The zip function creates an iterator that doesn't consume additional space proportional to the input size.

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

Common Pitfalls

1. Misunderstanding the "Strictly Greater" Requirement

Pitfall: A common mistake is using >= (greater than or equal) instead of > (strictly greater) when checking if you can defeat an opponent. This leads to unnecessary training hours.

Incorrect Implementation:

# WRONG: This trains even when energy/experience equals opponent's
if current_energy < opponent_energy:  # Should be <=
    training_hours += opponent_energy - current_energy
    current_energy = opponent_energy

Why it's wrong: If you have 5 energy and the opponent has 5 energy, you cannot defeat them. You need at least 6 energy (strictly greater than 5).

Correct Implementation:

# CORRECT: Train when energy is less than or equal to opponent's
if current_energy <= opponent_energy:
    training_hours += opponent_energy + 1 - current_energy
    current_energy = opponent_energy + 1

2. Training to Exact Match Instead of Exceeding

Pitfall: Training to exactly match the opponent's stats rather than exceeding them by at least 1.

Incorrect Implementation:

# WRONG: Only trains to match the opponent
if current_energy <= opponent_energy:
    training_hours += opponent_energy - current_energy
    current_energy = opponent_energy  # Should be opponent_energy + 1

Correct Implementation:

# CORRECT: Train to have at least opponent's value + 1
if current_energy <= opponent_energy:
    training_hours += opponent_energy + 1 - current_energy
    current_energy = opponent_energy + 1

3. Forgetting to Update Stats After Battle

Pitfall: Some solutions check and train correctly but forget to simulate the actual battle outcome, leading to incorrect calculations for subsequent opponents.

Incorrect Implementation:

for opponent_energy, opponent_experience in zip(energy, experience):
    if current_energy <= opponent_energy:
        training_hours += opponent_energy + 1 - current_energy
        current_energy = opponent_energy + 1
  
    if current_experience <= opponent_experience:
        training_hours += opponent_experience + 1 - current_experience
        current_experience = opponent_experience + 1
  
    # WRONG: Forgot to update stats after battle!
    # Missing: current_energy -= opponent_energy
    # Missing: current_experience += opponent_experience

Why it matters: After defeating opponent 1, your energy decreases and experience increases. These changes affect whether you need training for opponent 2.

4. Training Both Stats When Only One is Needed

Pitfall: Adding training hours for both energy and experience when only one stat is insufficient.

Incorrect Implementation:

# WRONG: Always adds training for both stats
energy_needed = max(0, opponent_energy + 1 - current_energy)
experience_needed = max(0, opponent_experience + 1 - current_experience)
training_hours += energy_needed + experience_needed  # Correct!

# But then incorrectly updating both regardless of need:
current_energy += energy_needed  # Should set to opponent_energy + 1 only if needed
current_experience += experience_needed  # Should set to opponent_experience + 1 only if needed

Correct Approach: Check each stat independently and only train/update if that specific stat is insufficient:

if current_energy <= opponent_energy:
    training_hours += opponent_energy + 1 - current_energy
    current_energy = opponent_energy + 1

if current_experience <= opponent_experience:
    training_hours += opponent_experience + 1 - current_experience
    current_experience = opponent_experience + 1

Prevention Tips:

  1. Always use <= in the condition check (not <)
  2. Always set to opponent_value + 1 (not just opponent_value)
  3. Always update both stats after each battle
  4. Test with edge cases where initial stats exactly match opponent stats
Discover Your Strengths and Weaknesses: Take Our 3-Minute Quiz to Tailor Your Study Plan:

Which of the following is a min heap?


Recommended Readings

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

Load More