1.题目链接:数青蛙 - LeetCode
2.题目描述
给定一个字符串 croakOfFrogs
,表示青蛙的鸣叫声序列。每个青蛙必须按顺序发出完整的 “croak” 字符,且多只青蛙可以同时鸣叫。要求计算最少需要多少只青蛙才能完成该字符串,若无法完成则返回 -1
。
示例:
输入:"croakcroak"
,输出:1
(一只青蛙可重复鸣叫两次)。
3.示例分析
以输入 "crcoakroak"
为例,分析过程如下:
- 第一个 ‘c’ 开始,对应青蛙1。
- 遇到第二个 ‘c’ 时,没有已完成的青蛙(此时青蛙1未完成),需新增青蛙2。
- 最终青蛙1和青蛙2交替完成各自的 “croak”,最终需要2只青蛙。
4.算法思路
核心思想
通过状态哈希表跟踪每个字符的状态,确保字符顺序合法,并复用已完成鸣叫的青蛙。
具体步骤
- 状态定义:使用数组
hash
记录每个字符(‘c’,‘r’,‘o’,‘a’,‘k’)的出现次数。 - 字符处理:
- 遇到 ‘c’ 时,优先复用已完成鸣叫的青蛙(
hash[4] > 0
)。 - 遇到其他字符时,必须存在前一个字符的状态(如 ‘r’ 前必须有 ‘c’)。
- 遇到 ‘c’ 时,优先复用已完成鸣叫的青蛙(
- 状态转移:每个字符处理时,减少前驱字符计数,增加当前字符计数。
- 结果验证:最终所有中间状态(‘c’,‘r’,‘o’,‘a’)必须清零,
hash[4]
的值即为最少青蛙数。
5.边界条件与注意事项
- 非法顺序:若字符出现时其前驱状态不存在(如直接出现 ‘r’ 而无 ‘c’),返回
-1
。 - 未完成状态:遍历结束后若中间状态未清零,说明存在未完成的鸣叫,返回
-1
。 - 首字符处理:遇到 ‘c’ 时若无可复用青蛙,需新增计数。
6.代码实现
class Solution {
public:int minNumberOfFrogs(string croakOfFrogs) {string base = "croak";int n = base.size();vector<int> hash(n, 0); // 记录各字符的状态数unordered_map<char, int> index; // 字符到索引的映射for (int i = 0; i < n; ++i) index[base[i]] = i;for (char ch : croakOfFrogs) {int idx = index[ch];if (ch == 'c') {// 复用已完成鸣叫的青蛙if (hash[n-1] > 0) hash[n-1]--;hash[0]++;} else {// 检查前驱状态是否存在if (hash[idx-1] == 0) return -1;hash[idx-1]--;hash[idx]++;}}// 验证中间状态是否清零for (int i = 0; i < n-1; ++i) {if (hash[i] != 0) return -1;}return hash[n-1];}
};
7.总结
本算法通过维护字符状态哈希表,实现了对青蛙鸣叫过程的精准模拟,时间复杂度为 O(n),空间复杂度 O(1)。关键在于复用青蛙和严格的状态转移检查,确保算法的效率与正确性。