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;
};
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:
-1
if the input is not a valid sequence of croaks.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.
We use an array or map for counters because lookups and updates are constant time (O(1)), making the algorithm efficient.
Let's use the input "croakcrookak"
as an example.
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.
This makes the optimized approach efficient and scalable, even for large inputs.
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.