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' ] ;
}
} ;