You are playing a game that consists of n levels. You are given a 0-indexed integer array damage where damage[i] is the amount of health you will lose to complete the ith level.
You are also given an integer armor. You may use your armor at most once during the game on any level which will protect you from at most armor damage. If the level has damage strictly less than armor, you are protected from all the damage.
Return the minimum health you need to start with to beat all the n levels.
Example 1:
Input: damage = [2,7,4,3], armor = 7 Output: 10 Explanation: Choose protecting level 1 with armor. Minimum health to start with = 2 + (7 - 7) + 4 + 3 = 10.
Example 2:
Input: damage = [2,5,3,4], armor = 7 Output: 12 Explanation: Choose protecting level 1 with armor. Minimum health to start with = 2 + (5 - 7) + 3 + 4 = 2 + 0 + 3 + 4 = 9.
Example 3:
Input: damage = [3,3,3], armor = 0 Output: 9 Explanation: You do not have armor, so you cannot reduce the damage at any level. Minimum health to start with = 3 + 3 + 3 = 9.
Constraints:
1 <= damage.length <= 1050 <= damage[i] <= 1050 <= armor <= 105When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
Imagine you're trying to find the smallest amount of starting health you need to survive a game where you encounter a series of challenges that either hurt or heal you. The brute force way is to simply guess a starting health, play the game, and see if you survive. If you don't, guess a higher starting health and try again until you find one that works.
Here's how the algorithm would work step-by-step:
def minimum_health_to_beat_game_brute_force(health_changes):
initial_health = 1
step = 1
while True:
current_health = initial_health
game_won = True
for health_change in health_changes:
current_health += health_change
if current_health <= 0:
game_won = False
break
if game_won:
# Found a health that works, try lower
test_health = initial_health - step
current_health = test_health
test_game_won = True
for health_change in health_changes:
current_health += health_change
if current_health <= 0:
test_game_won = False
break
if test_game_won:
# Trying lower health succeeded, lets decrease the initial
initial_health -= step
else:
# Lower health failed. Initial health is the min
return initial_health
else:
# Guess was too low, increase health.
initial_health += stepTo figure out the minimum health needed, we don't actually simulate playing the game. Instead, we work backwards and calculate the needed health in reverse order of levels, figuring out the minimum health needed to survive each encounter. This helps us efficiently arrive at the initial health required.
Here's how the algorithm would work step-by-step:
def minimum_health_to_beat_game(health_drain):
levels_count = len(health_drain)
# Initialize min health needed after last level.
minimum_health_needed = 1
for i in range(levels_count - 1, -1, -1):
# If health drain is positive, health is needed.
if health_drain[i] >= 0:
minimum_health_needed += health_drain[i]
else:
# Check if health gain reduces minimum needed.
if -health_drain[i] >= minimum_health_needed:
minimum_health_needed = 1
return minimum_health_needed| Case | How to Handle |
|---|---|
| Null or empty damage array | Return 1 if the array is null or empty as no damage is taken, requiring only 1 initial health. |
| Array with a single element | Return damage[0] + 1, since you need to survive the first and only stage. |
| Large array (performance considerations) | Ensure the algorithm has a time complexity that scales reasonably, ideally O(n) or O(n log n), to avoid timeouts. |
| All damage values are zero | Return 1 since no health is lost in any stage. |
| Damage values contain negative numbers | Treat negative damage as healing, and reduce the required initial health accordingly. |
| Extreme damage values leading to potential integer overflow | Use long data type or appropriate overflow detection and handling mechanisms. |
| The total damage exceeds the maximum representable integer value | Handle potential integer overflow by either using a larger data type or clamping the health to the maximum possible value. |
| Damage values include floating-point numbers | Convert all damage values to integers by rounding up (ceiling function) before calculating health to avoid precision issues and ensure the health is sufficient for the integer damage being taken. |