Start learning free

LESSON 314 OF 410 · HEAP

Kill Monsters - Java Solution with Time Complexity Analysis

Practice O(n log n) Read the full explanation

You are a hero in a game, initially having HP health points and K magic potions.

You have to fight N monsters in the order they are given, knowing the damage each monster deals to you.

damage[i] represents the damage the monster deals to you when you fight them. If the damage is negative, it means your HP increases by that amount.

If you use a magic potion on a monster, it will kill the monster without you fighting or losing health points.

If your HP drops below zero, you lose the fight. If it drops to exactly zero HP, you still kill that monster, but you are left with no health, so the fight ends there. Therefore you can't win against a monster that has damage[i] > HP.

Find the maximum number of monsters you can kill, considering you are playing optimally.

Example

Input: K = 2, HP = 10,
       damage = [-3, 2, 3, -2, 8, 8, 6, 4, 3, 3]
Output: 8
Explanation: You kill the first 8 monsters by using the two potions on the 5th and 6th monsters
STEP 1 OF 10
    Ctrl + Enter to check

    JAVA · HEAP

    Kill Monsters in Java, explained

    Understanding the Problem

    The core challenge of this problem is to maximize the number of monsters you can kill while managing your health points (HP) and the limited number of magic potions (K). The significance of this problem lies in its application to resource management and optimization scenarios, which are common in game development and real-world applications.

    Potential pitfalls include not using the potions optimally or mismanaging the HP, leading to an early death in the game.

    Approach

    To solve this problem, we need to consider both the damage dealt by each monster and the strategic use of potions. Here’s a step-by-step approach:

    1. Iterate through the list of monsters and keep track of the current HP.
    2. If the damage is negative, add it to the HP.
    3. If the damage is positive and can be survived, subtract it from the HP.
    4. If the damage is too high to survive, use a potion if available.
    5. Keep track of the number of monsters killed.

    We can use a priority queue to manage the damage values efficiently, ensuring that we use potions on the most damaging monsters first.

    Algorithm

    Here’s a detailed breakdown of the algorithm:

    1. Initialize a priority queue to keep track of the damage values.
    2. Iterate through the damage array:
      • If the damage is negative, add it to the HP and continue.
      • If the damage is positive and can be survived, subtract it from the HP and add it to the priority queue.
      • If the damage is too high to survive, use a potion if available, otherwise break the loop.
    3. Return the number of monsters killed.

    Code Implementation

    import java.util.PriorityQueue;
    
    public class KillMonsters {
        public static int maxMonstersKilled(int K, int HP, int[] damage) {
            // Priority queue to store the damage values
            PriorityQueue<Integer> pq = new PriorityQueue<>((a, b) -> b - a);
            int monstersKilled = 0;
    
            for (int dmg : damage) {
                if (dmg < 0) {
                    // If damage is negative, increase HP
                    HP += -dmg;
                } else {
                    // If damage is positive
                    if (HP > dmg) {
                        // If we can survive the damage, subtract it from HP
                        HP -= dmg;
                        pq.add(dmg);
                    } else if (K > 0) {
                        // If we can't survive but have potions, use one
                        K--;
                        pq.add(dmg);
                    } else {
                        // If we can't survive and have no potions, break
                        break;
                    }
                }
                monstersKilled++;
            }
    
            return monstersKilled;
        }
    
        public static void main(String[] args) {
            int K = 2;
            int HP = 10;
            int[] damage = {-3, 2, 3, -2, 8, 8, 6, 4, 3, 3};
            System.out.println(maxMonstersKilled(K, HP, damage)); // Output: 8
        }
    }
    

    Complexity Analysis

    The time complexity of this approach is O(N log N) due to the priority queue operations. The space complexity is O(N) for storing the damage values in the priority queue.

    Edge Cases

    Potential edge cases include:

    • All damage values are negative.
    • All damage values are higher than the initial HP.
    • Insufficient potions to survive the sequence of monsters.

    Each of these cases should be tested to ensure the algorithm handles them correctly.

    Testing

    To test the solution comprehensively, consider the following test cases:

    • Simple cases with a few monsters and potions.
    • Edge cases with all negative or all high damage values.
    • Complex cases with a mix of positive and negative damage values.

    Using a testing framework like JUnit can help automate and validate these test cases.

    Thinking and Problem-Solving Tips

    When approaching such problems, consider the following tips:

    • Break down the problem into smaller, manageable parts.
    • Think about the constraints and how they affect the solution.
    • Use data structures like priority queues to manage and optimize resources.
    • Practice similar problems to improve problem-solving skills.

    Conclusion

    In this blog post, we discussed how to solve the "Kill Monsters" problem using a priority queue to manage damage values and optimize the use of potions. We covered the problem definition, approach, algorithm, code implementation, complexity analysis, edge cases, and testing. Understanding and solving such problems is crucial for developing strong problem-solving skills and optimizing resource management in various applications.

    Additional Resources

    For further reading and practice, consider the following resources:

    • LeetCode - Practice coding problems and challenges.
    • GeeksforGeeks - Tutorials and articles on algorithms and data structures.
    • Coursera - Online courses on algorithms and problem-solving.
    Keep going with JavaAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free