LeetCode每日一题:1419. 数青蛙

638 阅读2分钟

1419. 数青蛙

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

注意:要想发出蛙鸣 "croak",青蛙必须 依序 输出 ‘c’, ’r’, ’o’, ’a’, ’k’ 这 5 个字母。如果没有输出全部五个字母,那么它就不会发出声音。

如果字符串 croakOfFrogs 不是由若干有效的 "croak" 字符混合而成,请返回 -1 。

来源:力扣(LeetCode)
链接:leetcode-cn.com/problems/mi…
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

示例:

输入: croakOfFrogs = "croakcroak"
输出: 1 
解释: 一只青蛙 “呱呱” 两次
输入:croakOfFrogs = "crcoakroak"
输出:2 
解释:最少需要两只青蛙,“呱呱” 声用大小写区分
第一只青蛙 "crcoakroak"
第二只青蛙 "CRcOAKroak"
输入: croakOfFrogs = "croakcrook"
输出: -1
解释: 给出的字符串不是 "croak " 的有效组合。

思路一 ---- 暴力循环查找(超时了 😭)

  • 如果入参的长度不是 5 的倍数,肯定不是符合要求的字符串,直接返回 -1
  • 符合要求的字符串,必然是以 C R O A K 这种顺序排序的,那么我们按顺序遍历,必然所有字段都可以被读取一次,否则就是不合法的,返回 -1
  • 因为我们需要查找的时最少的青蛙,所以我们只要查找 字符串 中什么时候 最多c 开始,又还没有 k 结束,就可以了,比如 CRcOAKroak 这个字段,大写的 C 表示第一只青蛙开始发声,但是还没结束,小写的 c 表示第二只青蛙开始发声,大写的 K 表示第一只青蛙结束了,如果后面还有 c 那么这第一只青蛙就可以再次发声,而不需要新的一只青蛙,所以我们只需要查找最大的同时发声的青蛙,就是题目的答案!

好像思路没啥问题,但是由于遍历次数过多,时间复杂度太高,所以这种解法是超时的!

class Solution {
    char[] CROAK = new char[]{'c','r','o','a','k'};
    public int minNumberOfFrogs(String croakOfFrogs) {
        if (croakOfFrogs.length()%5>0){
            return -1;
        }
        char[] croaks = croakOfFrogs.toCharArray();
        // 标记字符串有没有被读取过
        boolean[] check = new boolean[croaks.length];
        int index = 0;
        // 判断是否是合法的字符串
        for (int i = 0; i < croaks.length; i++) {
            if(check[i]){
               continue;
            }
            if (croaks[i] == CROAK[index]) {
                index++;
                check[i] = true;
            }
            // 如果找到一个croak,则从头开始查找下一个croak
            if(index == 5){
                i = 0;
                index = 0;
            }
        }
        // 当遍历结束,还有字段是没有被读取的,那么字符串不符合要求
        boolean flag = true;
        for (int i = 0; i < check.length; i++) {
            flag = flag && check[i];
        }
        if(flag){
            // 如果合法,则查找同时叫的青蛙的最大值
            int count = 0;
            int ts = 0;
            for (int i = 0; i < croaks.length; i++) {
                if (croaks[i]==CROAK[0]) {
                    // 一只青蛙开始叫了
                    count++;
                }
                if (croaks[i] == CROAK[4]){
                    // 一直青蛙结束了
                    count--;
                }
                ts = Math.max(count,ts);
            }
            return ts;
        }else {
            return -1;
        }
    }
}

思路二 ---- 一次循环 (成功了 😀)

由于暴力解法超时了,我们转换思路:

  • 我们知道符合要求的字符串,必然是以 C R O A K 这种顺序排序,那必然满足有以下两点
    • 青蛙叫必然是c 开始,k结束;
    • 遍历字符串的任意时刻,字母的出现次数 必然是 c>r>o>a>k,否则就是不合法的

根据以上两点

class Solution {
    public int minNumberOfFrogs(String croakOfFrogs) {
        if (croakOfFrogs.length()%5>0){
            return -1;
        }
        int length = croakOfFrogs.length();
        char[] chars = croakOfFrogs.toCharArray();
        int count = 0,ccount = 0,rcount = 0, ocount = 0, acount = 0, kcount = 0, ts = 0;
        for (int i = 0; i < length; i++) {
            // 遍历字符串,记录每个字符出现的次数 
            if (chars[i]=='c') {
                ccount++;
                count++;
            }
            if (chars[i]=='r') {
                rcount++;
            }
            if (chars[i]=='o') {
                ocount++;
            }
            if (chars[i]=='a') {
                acount++;
            }
            if (chars[i] == 'k'){
                kcount++;
                count--;
            }
            if(!(ccount>=rcount&&rcount>=ocount&&ocount>=acount&&acount>=kcount)){
                return -1;
            }
            ts = Math.max(count,ts);
        }
        return ts;
    }
}

记录每日刷 leetcode 的思路 和 想法; 

见证每 1 bit 成长; 

在线蹲赞环节  

老板!点赞!