# 题目描述

给你一个字符串 croakOfFrogs,它表示不同青蛙发出的蛙鸣声(字符串 "croak" )的组合。由于同一时间可以有多只青蛙呱呱作响,所以 croakOfFrogs 中会混合多个 “croak” 。

请你返回模拟字符串中所有蛙鸣所需不同青蛙的最少数目

要想发出蛙鸣 "croak",青蛙必须 依序 输出 ‘c’, ’r’, ’o’, ’a’, ’k’ 这 5 个字母。如果没有输出全部五个字母,那么它就不会发出声音。如果字符串 croakOfFrogs 不是由若干有效的 "croak" 字符混合而成,请返回 -1 。

  • 1 <= croakOfFrogs.length <= 105
  • 字符串中的字符只有 'c', 'r', 'o', 'a' 或者 'k'

# 示例

示例1:

输入:croakOfFrogs = "croakcroak" 输出:1 解释:一只青蛙 “呱呱” 两次

示例2:

输入:croakOfFrogs = "crcoakroak" 输出:2 解释:最少需要两只青蛙,“呱呱” 声用黑体标注 第一只青蛙 "crcoakroak" 第二只青蛙 "crcoakroak"

示例2:

输入:croakOfFrogs = "croakcrook" 输出:-1 解释:给出的字符串不是 "croak" 的有效组合。

# 思路

  • count[]来统计 "croak"的个数
  • c: 0, r: 1, o: 2, a: 3, k: 4
  • 每次访问到c时,维护青蛙个数 + 1
  • 访问其他字符时,让前一个字符减一(保证顺序),如果前一个字符对应的count < 0 则返回-1,然后让当前字符对应的count + 1
  • 访问到k时,前边的count必须也为0,维护青蛙个数 - 1
  • 最后count的值必须都是0, 如果有不为0,则返回-1

如果 croakOfFrogs 是有效的蛙鸣组合,则对于每个不是 'c' 的字母,蛙鸣中的上一个字母一定在 croakOfFrogs 中已经出现。例如,当 croakOfFrogs 中存在字母 'r' 时,一定在字母 'r' 之前有字母 'c'。假设字母 'c', 'r', 'o', 'a', 'k' 对应的下标分别是 0, 1, 2, 3, 4,则当遍历到下标为 index 的字母时,进行如下操作:

TIP

如何判断字符是符合条件 —— 按照croak的顺序 当 index > 0 时,将下标 index - 1 对应的计数减 1,如果在更新计数之后,下标 index - 1 对应的计数变成负数,则 croakOfFrogs 不是有效的蛙鸣组合,返回 -1;

# 代码

/**
 * @param {string} croakOfFrogs
 * @return {number}
 */
var minNumberOfFrogs = function(croakOfFrogs) {
    // count[]来统计 "croak"的个数
    // c: 0, r: 1, o: 2, a: 3, k: 4
    // 每次访问到c时,维护青蛙个数 + 1
    // 访问其他字符时,让前一个字符减一(保证顺序),如果前一个字符对应的count < 0 则返回-1,然后让当前字符对应的count + 1
    // 访问到k时,前边的count必须也为0,维护青蛙个数 - 1
    // 最后count的值必须都是0, 如果有不为0,则返回-1
    if(croakOfFrogs.length % 5 != 0){
        return -1;
    }
    let count = new Array(5).fill(0);
    // 当前青蛙个数
    let curSize = 0;
    // 最大青蛙个数
    let maxSize = 0;
    // 开始遍历
    for(let i = 0; i < croakOfFrogs.length; i ++){
        let index = getIndex(croakOfFrogs.charAt(i));
        if(index == 0){
            count[index] ++;
            curSize ++;
            maxSize = Math.max(maxSize, curSize);
        }
        else{
            // 保证有序
            count[index - 1] --;
            if(count[index - 1] < 0){
                return -1;
            }
            if(index != 4){
                count[index] ++;
            }
            else{
                curSize --;
            }
        }
    }
    for(let i of count){

        if(i != 0){
            return -1;
        }
    }
    return maxSize;
    
};
// 将字符转为count数组对应的下标
var getIndex = (c) => {
    if(c == 'c'){
        return 0;
    }
    else if(c == 'r'){
        return 1;
    }
    else if(c == 'o'){
        return 2;
    }
    else if(c == 'a'){
        return 3;
    }
    else{
        return 4;
    }
};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69

# 时间复杂度分析

  • 时间复杂度:O(n + |Σ|),其中 n 是字符串 croakOfFrogs 的长度,Σ 表示字符集,这道题中的字符集包含 'c', 'r', 'o', 'a', 'k',|Σ|=5。需要遍历字符串 croakOfFrogs 一次,以及需要遍历每个字母的计数一次。
  • 空间复杂度:O(|Σ|),其中 Σ 表示字符集,这道题中的字符集包含 'c', 'r', 'o', 'a', 'k',|Σ|=5。空间复杂度主要为对每个字符计数的空间。