こんにちは! mnbd(@mnbbbbbd)です。
AIZU ONLINE JUDGEの「ITP1_8_C 文字のカウント」を解いてみましたので、その回答と解説をご紹介いたします。
プログラミング初心者なので、もっといい回答があるに違いありません。
あくまでも「動作はする」サンプルとしてご覧ください。
問題文
与えられた英文に含まれる、各アルファベットの数を数えるプログラムを作成して下さい。 なお、小文字と大文字は区別しません。
複数の行にまたがる1つの英文が与えられます。
与えられた英文に含まれる各アルファベットの数を以下に示す形式で出力して下さい:
a : aの数
https://onlinejudge.u-aizu.ac.jp/courses/lesson/2/ITP1/8/ITP1_8_C
b : bの数
・
・
z : zの数
回答
#include <bits/stdc++.h>
using namespace std;
int main() {
char al[] = "abcdefghijklmnopqrstuvwxyz";
char ch;
int counter[26] = {};
while(cin >> ch) {
int num = tolower(ch) - 'a';
counter[num]++;
}
for(int i = 0; al[i] != '\0'; i++) {
cout << al[i] << " : " << counter[i] << endl;
}
return 0;
}
解説
はじめに出力表示するためのアルファベットの配列al、入力文字を入れる変数ch、各アルファベットのカウント数のための配列counterをそれぞれ確保しています。
入力から文字を受け取り変数chに格納しています。文字を一文字ずつ終了までループしてます。
読み込んだ文字を配列counterに格納しますが、ifやswich文で書くと長くなってします。
ここでは、文字のアスキーコードを利用します。
アスキーコードとは、コンピューターの理解できる0と1の数値を人間がわかる文字ひとつひとつに割り当てた規則のようなものだと私は理解しています。
たとえば、アルファベットの「t」は10進数で「116」となっています。
このアスキーコードでは、アルファベット順に数値が増加していますので、「t」の次の「u」は10進数で「117」となっています。
この規則を利用すると、たとえば、「t」を配列counterで格納したい場合、「t」(116)から「a」(97)を引くと「19」になりますね。
そうすると、counter[19]には「t」のカウント数が格納されることになるわけです。
これによりループの中が2行で済みます。条件分岐では20行以上になってしまいます。
全部の入力文字をカウントし終わったら、配列counterを指定の形式で出力しています。
ハマったポイント
受け取る入力をどのように終了させればいいのかがわかりませんでした。
これまでのAIZU ONLINE JUDGEでは、「入力値が0で終了」などのわかりやすいルールがあったので、それに則ってループを抜ける条件を書けばよかったのですが、この問題にはそれがありませんでした。
上記コードについて自分の環境(VSCode + MSYS2)では入力待ちになってしまいます。[Ctrl]+[C]で終了していましたが、出力動作は想定したものになりません。
結局わからずにこのままの上記コードを投稿したらWAでした。
ですから、いまだにこの問題については納得ができていないところがあります。
学んだこと
アスキーコードについて学びました。
文字処理の場合、こうした規則をうまく利用するとコードを簡素に書けるということですね。
それと出力用アルファベットを最初に配列で確保することで、ループの中を簡素に書けることも学びました。
配列counterも同様ですが、こうした知識があるのとないのとではまったく違いますね。
コードが長くなればそれだけバグを生みやすくなるわけですから。
まとめ
AIZU ONLINE JUDGEの「ITP1_8_C 文字のカウント」の回答と解説をご紹介いたしました。
私はまだ初心者ですが、よかったら一緒に勉強していきましょう。
Twitter(@mnbbbbbd)などをフォローしていただければ幸いです。
以上です。
読んでいただきありがとうございました。