1419.数青蛙 -- 学习心得记录

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. 能够发出声音的情况下,各个字符出现的次数必须满足 C n t c > C n t r > C n t o > C n t a > C n t k Cnt_c>Cnt_r>Cnt_o>Cnt_a>Cnt_k Cntc>Cntr>Cnto>Cnta>Cntk
      3. 否则直接返回-1
      4. 由于最终所要求最少需要多少个青蛙一齐哇鸣,所以各个字符出现的次数即为需要的最少青蛙数
  4. 如何求得所需要的最少青蛙数?
    1. 思路倒着来ex: croak; ans = 0
      1. 出现字符c,进行计数 C n t c = 1 Cnt_c = 1 Cntc=1,所需要青蛙数ans++
      2. 出现字符r,进行计数 C n t r = 1 Cnt_r = 1 Cntr=1并对 C n t c Cnt_c Cntc做减一操作,此时 C n t c = 0 Cnt_c=0 Cntc=0
      3. 依次类推
      4. 出现字符k,之后有 C n t k = 1 , C n t c , r , o , a = 0 , a n s = 1 Cnt_k = 1,Cnt_{c,r,o,a}=0,ans=1 Cntk=1,Cntc,r,o,a=0,ans=1
        1. 遍历完毕仅有 C n t k ! = 0 Cnt_k!=0 Cntk!=0
      5. 一次遍历完毕,判断是否满足 C n t c , r , o , a = 0 Cnt_{c,r,o,a}=0 Cntc,r,o,a=0,不满足直接跳出循环,返回-1
    2. 由于可能出现此种情况ex: croakccrrooaakk,很明显需要最少2个青蛙一齐鸣叫
      1. 当遍历到第二个字符c的时候, C n t k ! = 0 Cnt_k!=0 Cntk!=0
      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. 多多尝试

参考

https://leetcode.cn/problems/minimum-number-of-frogs-croaking/
https://leetcode.cn/problems/minimum-number-of-frogs-croaking/solution/cai-ji-gong-xian-ge-chun-onzuo-fa-by-imcover/

猜你喜欢

转载自blog.csdn.net/GoNewWay/article/details/130517514