Want Help Cracking FAANG?

(Then click this)

×
Back to Question Bank

1419. Minimum Number of Frogs Croaking - Leetcode Solution

Code Implementation

class Solution:
    def minNumberOfFrogs(self, croakOfFrogs: str) -> int:
        from collections import Counter
        croak = "croak"
        counts = Counter()
        frogs = 0
        max_frogs = 0

        for ch in croakOfFrogs:
            idx = croak.find(ch)
            if idx == 0:
                counts[ch] += 1
                frogs += 1
                max_frogs = max(max_frogs, frogs)
            else:
                prev = croak[idx - 1]
                if counts[prev] == 0:
                    return -1
                counts[prev] -= 1
                counts[ch] += 1
                if ch == 'k':
                    frogs -= 1

        if any(counts[c] for c in croak[:-1]):
            return -1
        return max_frogs
      
class Solution {
public:
    int minNumberOfFrogs(string croakOfFrogs) {
        vector<int> counts(5, 0);
        string croak = "croak";
        int frogs = 0, maxFrogs = 0;
        for (char ch : croakOfFrogs) {
            int idx = croak.find(ch);
            if (idx == 0) {
                counts[0]++;
                frogs++;
                maxFrogs = max(maxFrogs, frogs);
            } else {
                if (counts[idx - 1] == 0) return -1;
                counts[idx - 1]--;
                counts[idx]++;
                if (ch == 'k') frogs--;
            }
        }
        for (int i = 0; i < 4; ++i) {
            if (counts[i] != 0) return -1;
        }
        return maxFrogs;
    }
};
      
class Solution {
    public int minNumberOfFrogs(String croakOfFrogs) {
        int[] counts = new int[5];
        String croak = "croak";
        int frogs = 0, maxFrogs = 0;
        for (char ch : croakOfFrogs.toCharArray()) {
            int idx = croak.indexOf(ch);
            if (idx == 0) {
                counts[0]++;
                frogs++;
                maxFrogs = Math.max(maxFrogs, frogs);
            } else {
                if (counts[idx - 1] == 0) return -1;
                counts[idx - 1]--;
                counts[idx]++;
                if (ch == 'k') frogs--;
            }
        }
        for (int i = 0; i < 4; ++i) {
            if (counts[i] != 0) return -1;
        }
        return maxFrogs;
    }
}
      
var minNumberOfFrogs = function(croakOfFrogs) {
    let croak = "croak";
    let counts = Array(5).fill(0);
    let frogs = 0, maxFrogs = 0;
    for (let ch of croakOfFrogs) {
        let idx = croak.indexOf(ch);
        if (idx === 0) {
            counts[0]++;
            frogs++;
            maxFrogs = Math.max(maxFrogs, frogs);
        } else {
            if (counts[idx - 1] === 0) return -1;
            counts[idx - 1]--;
            counts[idx]++;
            if (ch === 'k') frogs--;
        }
    }
    for (let i = 0; i < 4; ++i) {
        if (counts[i] !== 0) return -1;
    }
    return maxFrogs;
};
      

Problem Description

You are given a string croakOfFrogs which represents the sequence of sounds made by several frogs croaking, possibly at the same time and possibly overlapping. Each frog can only croak the word "croak" in order ('c', 'r', 'o', 'a', 'k'). The string is a concatenation of these croaks, but the croaks may overlap in any way.

Your task is to determine the minimum number of frogs needed to produce the given sequence. If the sequence is invalid (for example, a frog tries to croak 'r' before 'c'), return -1.

Constraints:

  • Each frog must croak "croak" in order, and cannot skip or rearrange letters.
  • A frog cannot start a new croak until it finishes the previous one.
  • Return -1 if the input is not a valid sequence of croaks.

Thought Process

At first glance, it may seem like you need to simulate every frog and track each one's progress through the word "croak". However, this could quickly become inefficient if you create a new frog object for every letter.

A brute-force approach would be to keep a list of all frogs and their current position in "croak", assigning each letter to an available frog or creating a new one as needed. But this is slow and complicated.

Instead, we can optimize by counting how many frogs are at each stage of the croak. Each time a 'c' is encountered, it may represent a new frog starting. Each subsequent letter ('r', 'o', 'a', 'k') can only occur if there's a frog at the previous stage. When a frog reaches 'k', it finishes and becomes available to start again. The maximum number of frogs croaking at the same time is the answer.

Solution Approach

  • Step 1: Map the Croak Stages
    The word "croak" has 5 letters. We'll keep a counter for each stage: how many frogs are at 'c', 'r', 'o', 'a', and 'k'.
  • Step 2: Process Each Character
    For each character in the input string:
    • If it's 'c', increment the 'c' counter (a frog starts croaking).
    • For any other character, check if there's a frog at the previous stage. If not, the sequence is invalid.
    • Move the frog from the previous stage to the current one (decrement previous, increment current).
    • When a frog finishes at 'k', decrement the 'k' counter and also decrement the number of active frogs.
  • Step 3: Track Maximum Frogs
    Each time a 'c' is encountered, increment the current number of active frogs. Each time a 'k' is encountered, decrement it. The maximum value reached during this process is the answer.
  • Step 4: Validate Completion
    At the end, all counters except for 'k' should be zero. If not, return -1 since some frogs did not finish croaking.
  • Step 5: Return the Answer
    Return the maximum number of frogs active at any point, or -1 if invalid.

We use an array or map for counters because lookups and updates are constant time (O(1)), making the algorithm efficient.

Example Walkthrough

Let's use the input "croakcrookak" as an example.

  • Step 1: 'c' → Start frog 1 (frogs = 1, max = 1)
  • Step 2: 'r' → Move frog 1 to 'r'
  • Step 3: 'o' → Move frog 1 to 'o'
  • Step 4: 'a' → Move frog 1 to 'a'
  • Step 5: 'k' → Frog 1 finishes (frogs = 0)
  • Step 6: 'c' → Start frog 2 (frogs = 1, max = 1)
  • Step 7: 'r' → Move frog 2 to 'r'
  • Step 8: 'o' → Move frog 2 to 'o'
  • Step 9: 'o' → Invalid! There is no frog waiting at 'o' (should be at 'r').

In this example, the function would return -1 because the sequence is invalid. In a valid input like "croakcroak", the process would show that at most 1 frog is needed.

Time and Space Complexity

  • Brute-force Approach: O(N²) time and O(N) space, since you might track every frog's progress individually.
  • Optimized Approach: O(N) time and O(1) space.
    • We only scan the input string once (N = length of input).
    • We use a fixed number (5) of counters, regardless of input size.

This makes the optimized approach efficient and scalable, even for large inputs.

Summary

The key insight is to avoid simulating each frog individually. Instead, by tracking how many frogs are at each stage of the word "croak", we can efficiently process the sequence in one pass. The maximum number of frogs simultaneously croaking gives the answer, and careful validation ensures correctness. This approach is both elegant and highly efficient.