1. 题目
2. 思路
- 题目说到了, 会混杂着青蛙的叫声, 如果字符串 croakOfFrogs 不是由若干有效的 “croak” 字符混合而成,请返回 -1, 那就是说如果有多余的
'c', 'r', 'o'
等等, 比如 "croakcroa"
; - 题目说了, 同一时间内可以有多只青蛙呱呱作响, 但是求的是模拟蛙鸣需要的不同青蛙的最少数目;
- 见上图, 都是 3个
croak
, 为什么左边最少需要青蛙的个数就是3只, 而右边需要青蛙的最少数量就可以是2只?
- 一只青蛙叫完一定是按照
顺序
, 依次去发出 c, r, o, a, k
这5个字母的, 最终结尾一定是'k'
, 一旦出现这种 croakx(x指的是任意字符)
即 字符k
之后还有其他的字符, 一定是不完整的蛙声, 即 return -1;
也就是说我们可以遍历叫声字串,能最终到了'k'
(如果不按顺序的, 比如 crkoa, k 之前应该是 a, 这样是到不了k的)说明收集到完整的青蛙蛙鸣, 那么过程中怎么统计青蛙数量?【判定是最少的】记住,遇到'c'
起始说明是需要青蛙叫的(可以是之前的青蛙, 或者一只新的青蛙);具体思路如下:
- 可以将青蛙叫分成5种:
3.1 刚才发出了 c 的声音;
3.2 刚才发出了 r 的声音;
3.3 刚才发出了 o 的声音;
3.4 刚才发出了 a 的声音;
3.5 刚才发出了 k 的声音; - 遍历croakOfFrogs, 例如当前遍历到 r,那么就看看有没有青蛙刚才发出了 c 的声音,如果有,那么才能让它接着发出 r 的声音;
4.1 用一个哈希表(数组)cnt 来维护这 c r o a k这五种青蛙的个数【cnt['c'] = 3, 说明发出 'c' 的 青蛙有3只】
, 然后可能的种类就这么几种情况:
4.2 遍历到 字符 'c'
时,看看有没有青蛙刚才发出了 字符'k'
的声音,如果有,那么复用这只青蛙(认为他还可以接着发出 下一个 蛙鸣 croak),让它接着发出 字符 'c'
的声音,即 cnt[‘k’]-- 和 cnt[‘c’]++;如果没有这种青蛙,那么直接新产生一只青蛙发出 c 的声音,即 cnt[‘c’]++;
4.3 遍历到 'r'
时,看看有没有青蛙刚才发出了 字符 'c'
的声音,如果有,那么复用这只青蛙,(同一只青蛙)让它接着发出 r 的声音,即 cnt[‘c’]-- 和 cnt[‘r’]++;如果没有这种青蛙,由于题目要求青蛙必须从 c 开始蛙鸣,不能直接从 r 开始【即 cnt[‘c’] == 0, 不能直接r开始】,所以返回 −1;
4.4 遍历到 o,a,k
的情况类似 r
, 我们要做的就是找到这个字母的上一个字母对应映射cnt[‘x’] 有没有 > 0, 有就 -1, 说明可以复用, 并且当前的字母的cnt值+1, 但是 如果上一个字母的 cnt 值等于 0,那么就返回 −1 - 遍历结束后,所有青蛙必须在最后发出 k 的声音,如果有青蛙在最后发出的声音不是 k(也就是 cnt 值大于 0),那么返回 −1,否则返回 cnt[k];
3. 代码
class Solution {
public:
int minNumberOfFrogs(string croakOfFrogs) {
const int N = 256;
vector<char> vctPre(N);
const string croak = "croakc";
for (int i = 1; i < 6; ++i){
vctPre[croak[i]] = croak[i - 1];
}
vector<int> res(N, 0);
for(const auto& frog : croakOfFrogs){
auto pre = vctPre[frog];
if (res[pre]){
res[pre]--;
}else if (frog != 'c'){
return -1;
}
res[frog]++;
}
if (res['c'] || res['r'] || res['o'] || res['a']){
return -1;
}
return res['k'];
}
};