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 levelexperience[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]
- Your energy decreases by
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.
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:
-
Check energy requirement: If my current energy
x
is not greater than opponent's energydx
, I need to train until I havedx + 1
energy. This requiresdx + 1 - x
hours of energy training. -
Check experience requirement: Similarly, if my current experience
y
is not greater than opponent's experiencedy
, I needdy + 1 - y
hours of experience training. -
Update stats after victory: Once we ensure we can defeat the opponent, we simulate the battle - subtract
dx
from our energy and adddy
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 opponenti+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 asinitialEnergy
)y
= current experience (starts asinitialExperience
)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]
:
-
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 thandx
, we need to train. We calculate exactly how many hours needed:dx + 1 - x
(to reachdx + 1
). -
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 thandy
, train until we havedy + 1
experience. -
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 EvaluatorExample 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:
- Always use
<=
in the condition check (not<
) - Always set to
opponent_value + 1
(not justopponent_value
) - Always update both stats after each battle
- Test with edge cases where initial stats exactly match opponent stats
Which of the following is a min heap?
Recommended Readings
Greedy Introduction div class responsive iframe iframe src https www youtube com embed WTslqPbj7I title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture web share allowfullscreen iframe div When do we use greedy Greedy algorithms tend to solve optimization problems Typically they will ask you to calculate the max min of some value Commonly you may see this phrased in the problem as max min longest shortest largest smallest etc These keywords can be identified by just scanning
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Donβt Miss This!