3207. Maximum Points After Enemy Battles
Problem Description
You are given an integer array enemyEnergies
representing the energy values of various enemies. You also have an integer currentEnergy
, representing the amount of energy you start with. Initially, you have 0 points, and all enemies are unmarked.
You can use either of the following operations, zero or multiple times, to gain points:
-
Select an unmarked enemy
i
ifcurrentEnergy >= enemyEnergies[i]
. By doing this:- Gain 1 point.
- Reduce your energy by the enemy's energy:
currentEnergy = currentEnergy - enemyEnergies[i]
.
-
If you have at least 1 point, select an unmarked enemy
i
. By doing this:- Increase your energy by the enemy's energy:
currentEnergy = currentEnergy + enemyEnergies[i]
. - The enemy
i
is marked.
- Increase your energy by the enemy's energy:
Your task is to return an integer representing the maximum points you can achieve by optimally performing these operations.
Intuition
The problem revolves around gaining the maximum number of points by strategically managing your energy and the marking of enemies. The solution leverages a greedy approach with sorting.
Hereโs the thought process:
-
Sort the Enemies: Start by sorting the enemies based on their energy values. This allows you to always assess minimal energy first, which is crucial as it lets you defeat weaker enemies easily and accumulate points without exhausting all your energy readily.
-
Maximize Points with Lowest Energy Enemies: By defeating enemies from the lowest energy value to the highest, you are ensuring that you gather more points by marking weaker enemies first since they cost less energy.
-
Energy Management and Recovery: Use the points you accumulate to potentially mark stronger enemies, thereby recovering energy. This is an important part of the strategy because marking higher energy enemies can replenish your energy, allowing you to defeat additional weaker foes and further maximize points.
In essence, the approach ensures a balance between utilizing minimal energy to gain points and strategically recovering energy to sustain the fight. This looping action continues until all foes are marked or no further actions can be taken, ensuring the highest score possible.
Learn more about Greedy patterns.
Solution Approach
In this solution, we adopt a greedy approach combined with sorting to maximize the points:
-
Sort the Array: Begin by sorting
enemyEnergies
in ascending order. This ordering is crucial since it allows you to deal with the enemies demanding the least energy first. -
Iterate Over Enemies: Utilize a loop to examine each enemy's energy value from low to high. For each enemy:
-
Attack with Sufficient Energy: If the
currentEnergy
is greater than or equal to an enemy's energy, use the attack operation. This increases your points by 1 and reducescurrentEnergy
by the enemy's energy. -
Energy Recovery with Points: If you have any points, consider if marking (i.e., sacrificing a point to regain energy from a marked enemy) is beneficial. This strategy involves recovering energy using the enemy with the highest energy value you have encountered and not yet marked.
-
-
Maximize Points: The loop continues until you can neither defeat another enemy nor does marking provide a strategic benefit. Throughout this process, ensure that energy usage is optimized to achieve the maximum number of points.
The implemented code logic in Python can be summarized as follows:
class Solution:
def maximumPoints(self, enemyEnergies: List[int], currentEnergy: int) -> int:
enemyEnergies.sort() # Step 1: Sort the enemies by energy requirement
ans = 0 # Initialize points
left, right = 0, len(enemyEnergies) - 1 # Two pointers for smallest and largest
# Step 2: Use a [greedy](/problems/greedy_intro) strategy to maximize points
while left <= right:
if currentEnergy >= enemyEnergies[left]:
# Attack to gain a point if energy allows
currentEnergy -= enemyEnergies[left]
ans += 1
left += 1
elif ans > 0:
# Use a point to regain energy if possible
currentEnergy += enemyEnergies[right]
ans -= 1
right -= 1
else:
# Break when no more progress can be made
break
return ans
This solution effectively balances point accumulation through attack operations and strategic energy recovery through marking, ensuring the optimal strategy is employed throughout. It handles efficient computation using sorting and while-loop based greedy checking to assure maximum points accumulation.
Ready to land your dream job?
Unlock your dream job with a 2-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's take a concrete example to illustrate the solution approach. Suppose we have:
enemyEnergies = [2, 3, 4, 5]
currentEnergy = 5
We aim to determine the maximum points we can achieve. Here's how the solution unfolds step-by-step:
-
Sort the Array: Start by sorting
enemyEnergies
, but since[2, 3, 4, 5]
is already sorted, we proceed with the same array. -
Initialization:
- Initialize
ans = 0
to keep track of points. - Use two pointers,
left = 0
(pointing to the smallest energy enemy) andright = 3
(pointing to the largest energy enemy).
- Initialize
-
Iterate Over Enemies:
-
First Loop Iteration:
currentEnergy = 5
,enemyEnergies[left] = 2
. Since5 >= 2
, use the attack operation:- Gain 1 point (
ans = 1
). - Reduce
currentEnergy
by 2 (currentEnergy = 3
). - Move
left
to the next enemy (left = 1
).
- Gain 1 point (
-
Second Loop Iteration:
currentEnergy = 3
,enemyEnergies[left] = 3
. Since3 >= 3
, use the attack operation:- Gain another point (
ans = 2
). - Reduce
currentEnergy
by 3 (currentEnergy = 0
). - Move
left
to the next enemy (left = 2
).
- Gain another point (
-
Third Loop Iteration:
currentEnergy = 0
, unable to attackenemyEnergies[left] = 4
.- Utilize a point to increase energy. Sacrifice 1 point (
ans = 1
) and mark the enemy with the highest energy (enemyEnergies[right] = 5
). - Increase
currentEnergy
by 5 (currentEnergy = 5
). - Move
right
to the previous enemy (right = 2
).
-
Fourth Loop Iteration:
currentEnergy = 5
,enemyEnergies[left] = 4
. Since5 >= 4
, use the attack operation:- Gain a point (
ans = 2
). - Reduce
currentEnergy
by 4 (currentEnergy = 1
). - Move
left
to the next enemy (left = 3
).
- Gain a point (
-
-
Break Condition:
- Cannot perform more actions since
currentEnergy < enemyEnergies[left]
and no more points to use for energy recovery.
- Cannot perform more actions since
The maximum points achieved is 2. This process strategically balances gaining points with attacks and recovering energy when needed, ensuring the optimal result.
Solution Implementation
1from typing import List
2
3class Solution:
4 def maximumPoints(self, enemyEnergies: List[int], currentEnergy: int) -> int:
5 # Sort the energies of the enemies in ascending order
6 enemyEnergies.sort()
7
8 # If we don't have enough energy to defeat the weakest enemy, return 0
9 if currentEnergy < enemyEnergies[0]:
10 return 0
11
12 # Initialize the maximum points we can achieve
13 max_points = 0
14
15 # Traverse the list of enemies from the strongest to the weakest
16 for i in range(len(enemyEnergies) - 1, -1, -1):
17 # Calculate how many times we can beat the weakest enemy with our current energy
18 max_points += currentEnergy // enemyEnergies[0]
19
20 # Reduce the current energy by the total energy used to defeat the weakest enemy multiple times
21 currentEnergy %= enemyEnergies[0]
22
23 # Add back the energy of the current enemy (considering we beat this enemy last)
24 currentEnergy += enemyEnergies[i]
25
26 return max_points
27
1import java.util.Arrays;
2
3class Solution {
4 public long maximumPoints(int[] enemyEnergies, int currentEnergy) {
5 // Sort enemy energies in ascending order
6 Arrays.sort(enemyEnergies);
7
8 // If the current energy is less than the weakest enemy's energy, return 0
9 if (currentEnergy < enemyEnergies[0]) {
10 return 0;
11 }
12
13 long points = 0; // Initialize points counter
14
15 // Loop over the enemies from the strongest to the weakest
16 for (int i = enemyEnergies.length - 1; i >= 0; --i) {
17 // Accumulate points by using the smallest enemy's energy as the divisor
18 points += currentEnergy / enemyEnergies[0];
19 // Update current energy after defeating enemies
20 currentEnergy %= enemyEnergies[0];
21 // Regain energy by defeating the current enemy
22 currentEnergy += enemyEnergies[i];
23 }
24
25 return points; // Return the maximum calculated points
26 }
27}
28
1#include <vector>
2#include <algorithm>
3
4class Solution {
5public:
6 long long maximumPoints(std::vector<int>& enemyEnergies, int currentEnergy) {
7 // Sort enemyEnergies in ascending order
8 std::sort(enemyEnergies.begin(), enemyEnergies.end());
9
10 // If the current energy is less than the smallest enemy energy, return 0
11 if (currentEnergy < enemyEnergies[0]) {
12 return 0;
13 }
14
15 long long totalPoints = 0;
16
17 // Traverse enemyEnergies from back to front
18 for (int i = enemyEnergies.size() - 1; i >= 0; --i) {
19 // Add as many points as current energy allows divided by smallest energy
20 totalPoints += currentEnergy / enemyEnergies[0];
21
22 // Get remainder of current energy when divided by smallest energy
23 currentEnergy %= enemyEnergies[0];
24
25 // Increase current energy by the i-th enemy energy value
26 currentEnergy += enemyEnergies[i];
27 }
28
29 return totalPoints;
30 }
31};
32
1/**
2 * Function to calculate the maximum points you can obtain with current energy
3 * by defeating enemies with specified energies.
4 *
5 * @param enemyEnergies - Array of energies of the enemies.
6 * @param currentEnergy - Initial energy you have.
7 * @returns The maximum points that can be achieved.
8 */
9function maximumPoints(enemyEnergies: number[], currentEnergy: number): number {
10 // Sort enemy energies in ascending order
11 enemyEnergies.sort((a, b) => a - b);
12
13 // If current energy is less than the smallest enemy energy, return 0 immediately
14 if (currentEnergy < enemyEnergies[0]) {
15 return 0;
16 }
17
18 let maxPoints = 0;
19
20 // Traverse the sorted enemy energies in reverse order
21 for (let i = enemyEnergies.length - 1; i >= 0; --i) {
22 // Calculate points scored by defeating as many smallest energy enemies as possible
23 maxPoints += Math.floor(currentEnergy / enemyEnergies[0]);
24
25 // Update the remaining energy after defeating the smallest energy enemies
26 currentEnergy %= enemyEnergies[0];
27
28 // Add back the energy of the current enemy
29 currentEnergy += enemyEnergies[i];
30 }
31
32 return maxPoints;
33}
34
Time and Space Complexity
The time complexity of the code is O(n log n)
due to the sorting of enemyEnergies
. The space complexity is O(log n)
because of the stack space used by the sorting algorithm, which is often implemented as a quick sort or merge sort.
Learn more about how to find time and space complexity quickly.
You are given an array of intervals where intervals[i] = [start_i, end_i]
represent the start and end of the ith
interval. You need to merge all overlapping intervals and return an array of the non-overlapping intervals that cover all the intervals in the input.
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 algomonster s3 us east 2 amazonaws com recursion jpg You first
Want a Structured Path to Master System Design Too? Donโt Miss This!