C++
 Computer >> コンピューター >  >> プログラミング >> C++

C++で解く「鳴くカエルの最小数」問題

問題概要

croakOfFrogs という文字列が与えられます。この文字列は、複数のカエルが発する「croak」という鳴き声が混ざり合ってできています。複数のカエルが同時に鳴くこともあるため、複数の「croak」が入り混じった状態になっています。

ここでの課題は、与えられた文字列に含まれるすべての鳴き声を完成させるために必要な「カエルの最小匹数」を求めることです。

有効な「croak」とは、1匹のカエルが 'c''r''o''a''k' の5文字を必ずこの順番で発声することを指します。カエルは5文字すべてを出し切って初めて1回の鳴き声が完了します。もし文字列が有効な「croak」の組み合わせとして成立しない場合は -1 を返します。

たとえば入力が "crcoakroak" の場合、出力は 2 になります。1匹目のカエルが先に鳴き始め、その途中で2匹目のカエルが加わることで、合計2匹ですべての鳴き声を完成できるためです。

解法のアプローチ

この問題は、次の手順に従って解きます。

  • 各文字の出現回数を記録するマップ m を用意する。
  • サイズ5の配列 ch{'c', 'r', 'o', 'a', 'k'} で初期化する。
  • temp = 0(現在鳴いているカエルの数)、ret = 0(答え)とする。
  • 文字列 s の各文字 c について以下を繰り返す。
    • m[c] を1増やす。
    • maxVal = m[ch[0]] とする。
    • i を 0〜4 まで動かしながら、maxVal < m[ch[i]] または m[ch[i]] < 0 の場合は -1 を返す。そうでなければ maxVal = m[ch[i]] で更新する。これにより、「前の音より後の音の数が多くなっていないか」、つまり鳴き声の順序が崩れていないかを常に検証できます。
    • c'c' なら temp を1増やす(新しいカエルが鳴き始めた)。
    • c'k' なら temp を1減らす(1匹分の鳴き声が完了した)。
    • ret = max(ret, temp) として、同時に鳴いていたカエル数の最大値を記録する。
  • 最後に i を 1〜4 まで確認し、m[ch[0]] != m[ch[i]] なら -1 を返す。すべての文字の個数が一致していなければ、途中で打ち切られた鳴き声が残っていることを意味します。
  • ret を返す。

ポイント解説

変数 temp は「'c' を発声したものの、まだ 'k' で完了していないカエル」、すなわち現在同時に鳴いているカエルの数を表しています。処理中の最大値を ret に記録しておけば、それがまさに必要なカエルの最小匹数となります。さらに、文字ごとの出現回数チェックによって、音の順序が不正な文字列や未完了の鳴き声を含む文字列を -1 として正しく除外できます。

実装例

理解を深めるために、以下のC++による実装を見てみましょう。

#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
   int minNumberOfFrogs(string s) {
      map<char, int> m;
      char ch[5] = { 'c', 'r', 'o', 'a', 'k' };
      int temp = 0;
      int ret = 0;
      for (auto& c : s) {
         m[c]++;
         int maxVal = m[ch[0]];
         for (int i = 0; i < 5; i++) {
            if (maxVal < m[ch[i]] || m[ch[i]] < 0) {
               return -1;
            }
            maxVal = m[ch[i]];
         }
         if (c == 'c') {
            temp++;
         }
         else if (c == 'k') {
            temp--;
         }
         ret = max(ret, temp);
      }
      for (int i = 1; i < 5; i++) {
         if (m[ch[0]] != m[ch[i]])
            return -1;
      }
      return ret;
   }
};
main(){
   Solution ob;
   cout << (ob.minNumberOfFrogs("crcoakroak"));
}

入力

"crcoakroak"

出力

2
  1. C++で質素数(Frugal Number)を判定する方法【サンプルコード付き】

    この記事では、正の整数 N が与えられたときに、その数が質素数(Frugal Number)であるかどうかを判定するプログラムを C++ で作成する方法を解説します。 質素数とは? 質素数(FRUGAL NUMBER)とは、その数自身の桁数が、素因数分解による表現の桁数よりも厳密に大きい数のことです。 例:625 の場合 625 を素因数分解すると 54 となります。 625 自身の桁数:3 桁 54 の表現の桁数:2 桁 3 は 2 よりも厳密に大きいため、625 は質素数です。 最初のいくつかの質素数:125、128、243、256、343、512、625 など 問題を理解するための具

  2. C++で五胞体数(ペンタトープ数)を求める方法

    五胞体数とは? 五胞体数(ペンタトープ数)は、パスカルの三角形の第5の対角線上に現れる数列として知られています。この数列を定義するには、パスカルの三角形に少なくとも5つの数が必要となるため、数列の最初の数はパスカルの三角形の第4行である 1 4 6 4 1 から始まります。 本チュートリアルでは、n番目の五胞体数を求める方法を解説します。まずは具体的な例を見てみましょう。 入力 : 1出力 : 1入力 : 4出力 : 35 以下の図から出力を確認できます。 この問題は数列に関するものなので、解法ではまず数列のパターンを見つけることから始めます。 解法のアプローチ このプログラムでは、数列の