1419.数青蛙 -- 学习总结

241 阅读3分钟

image.png

题目解析

  1. 一声有效的“蛙鸣”,必须依次输出字符c r o a k,例如corak所组成的字符串不会发出声音
    1. 一只青蛙无论怎么鸣叫,其结果必定是字符串croak的重复
    2. 鸣叫n声,则重复ncroak
  2. 两只青蛙一齐鸣叫一次的结果是字符c r o a k的组合,即有如下可能
    1. croakcroak
      1. croakcroak可以代表两只青蛙一齐鸣叫的一种结果,也可以代表一只青蛙连续鸣叫两次
      2. 所以,才有所求——所需青蛙的最少数目
    2. crcoakroak
      1. 如下图
    3. image.png

思路分析

  1. 代表蛙鸣的字符串组成有且仅有'c' 'r' 'o' 'a' 'k'
  2. 能发出声音的组合必须是 c->r->o->a->k
    1. 有效哇鸣,字符c必须前面,字符k必须在最后面
  3. 遍历给定的代表哇鸣的字符串croakOfFrogs
    1. 用五个变量分别对字符'c' 'r' 'o' 'a' 'k'进行计数
    2. 假设一组哇鸣中,最少需要 n 个青蛙一起鸣叫组成
      1. 那么肯定有 n 个字符 c 先于 n个字符r出现
      2. 字符 r 先于字符 o 出现
      3. 字符 o 先于字符 a 出现
      4. 字符 a 先于字符 k 出现
    3. 在遍历过程中记录各个字符出现的次数,最终每一个字符出现的字符次数相同
      1. 并且在遍历过程中按照顺序c->r->o->a->k依次出现的次数
      2. 能够发出声音的情况下,各个字符出现的次数必须满足
      3. 否则直接返回-1
      4. 由于最终所要求最少需要多少个青蛙一齐哇鸣,所以各个字符出现的次数即为需要的最少青蛙数
  4. 如何求得所需要的最少青蛙数?
    1. 思路倒着来ex: croak; ans = 0
      1. 出现字符c,进行计数,所需要青蛙数ans++
      2. 出现字符r,进行计数并对做减一操作,此时
      3. 依次类推
      4. 出现字符k,之后有
        1. 遍历完毕仅有
      5. 一次遍历完毕,判断是否满足,不满足直接跳出循环,返回-1
    2. 由于可能出现此种情况ex: croakccrrooaakk,很明显需要最少2个青蛙一齐鸣叫
      1. 当遍历到第二个字符c的时候,
      2. 所以出现字符c的时候需要判断
        1. k > 0,k--
        2. 否则ans++

code

    public int minNumberOfFrogs(String croakOfFrogs) {
        int n = croakOfFrogs.length();
        // 必须是5的倍数
        if(n % 5 != 0) {
            return -1;
        }
        // 计数变量
        int c,r,o,a,k;
        c = r = o = a = k = 0;
        // 所需青蛙数
        int ans = 0;
        for(int i = 0;i < n;i++) {
            char at = croakOfFrogs.charAt(i);
            if(at == 'c') {
                c++;
                if(k > 0) {
                    k--;
                } else {
                    ans++;
                }
            } else if(at == 'r') {
                r++;
                c--;
            } else if(at == 'o') {
                o++;
                r--;
            } else if(at == 'a') {
                a++;
                o--;
            } else if(at == 'k') {
                k++;
                a--;
            }
            //出现 小于 0的情况,字符串无效
            if(c < 0 || r < 0 || o < 0 || a < 0) {
                return -1;
            }
        }

        // 遍历完成需要满足  c = r = o = a = 0;
        if(c != 0 || r != 0 || o != 0 || a != 0) {
            return -1;
        }
        return ans;
    }

心得体会

  1. 巧妙利用了字符顺序出现的性质,利用计数的方法解决
    1. 计数过程中的加减转化颇为巧妙
  2. 要灵活运用题目中所给出的已知条件
  3. 不要钻牛角尖
  4. 再次遇到字符串相关题目要有以下思路
    1. 是否可以计数解决
    2. KMP解决(从一个字符串中寻找另外一个字符串出现的次数)
    3. manacher算法(回文串)
    4. 二分查找
  5. 多多尝试

参考

leetcode.cn/problems/mi… leetcode.cn/problems/mi…