GoumbikによるPixabayからの画像
こんにちは。倉内です。
自宅で過ごす時間が長くなり、これを機にプログラミング学習に取り組んでみようと考えている方も多いですよね。
まずは基本的な文法を学ぶところから取り掛かると思いますが、どれだけ身についているかを測るにはプログラミング問題を解いてみるのがおすすめです。
インプットはもちろん大切ですが、自分でコードを書いてアウトプットしてみると、理解不足や苦手な点が明らかになるので、そこを重点的に学習すればよいということが分かります。
今回は初学者の方が、プログラミング問題を解く際に押さえておいたほうがよい基本知識をPythonで実際にコードを書きながら説明します。
また、競技プログラミングの問題を解く際に必要になる「標準入力」についても入力パターン別に解説したいと思います。
(準備)基礎文法の習得
今回は初心者でも学習しやすいPythonを例に解説しますが、「プログラミングというものに今初めて触れる」という方は体験編や入門編の学習講座を受講してからのほうがスムーズに理解していただけると思います。
すべてのレッスンを受講するとPythonの基本が網羅できておすすめですが、入門編の後半はちょっと難しいところもあるので、まずは全編無料の体験編を受講しておけばよいでしょう。
ちなみにpaizaラーニングでは、Pythonの他にPHP、Ruby、Java、C、C#、JavaScriptなどの体験編・入門講座も公開しています。講座一覧はこちら
言語ごとに特徴はありますが、考え方はどの言語でもほとんど同じなので目的や好みに合わせて選んでください。
プログラミング問題を解くための基本知識
ここからは練習問題を集めた「レベルアップ問題集」で公開している問題を用いて、初学者の方がつまずきやすいポイントと考え方をお伝えしていきます。
書いたコードはpaiza.IOを使ってブラウザ上で実行確認できます。
標準入力とは:パターン別入力値の受け取り方
プログラミング問題では、与えられた数値や文字列を条件に沿って処理をして正しい結果を出力できるかが問われることが多いのですが、「与えられた値を取る」ところが慣れるまで難しいと感じる人が多いようです。
そのためまずはいくつかのパターンで標準入力処理のコードを書けるように練習しましょう。Pythonでは値を受け取るときは input 関数を使い、値を出力するときは print 関数を使います。
1つのデータの入力
- 文字列が1つ1行で与えられる
# 変数stringにinputで取得した文字列を入れて、printで出力する string = input() print(string)
- 数値が1つ1行で与えられる
input関数は数値が渡されても文字列で取得するので、int() で数値に変換する必要があります。
# 変数numにinputで取得した文字列を数値(int型)に変換して入れて、 # printで出力する num = int(input()) print(num)
1行のデータの入力
次はさきほどと同じ1行ですが、「スペース」や「カンマ」で区切られた複数の値を取得する処理を書きます。区切って1つずつにするには split 関数を使います。
- 文字列がスペース区切りで3つ与えられる
s1, s2, s3 = input().split() print(s1) print(s2) print(s3)
- 数値がカンマ区切りで2つ与えられる
数値として取りたいときは map 関数を使います。
n1, n2 = map(int, input().split(",")) print(n1) print(n2)
- 数値がカンマ区切りで複数与えられる
実は値を入れる変数を宣言しなくても、与えられる分だけリストに入れられます。Pythonは特にこの書き方が分かりやすいと思います。
input_list = input().split(",") print(input_list)
たとえば、このとき入力値が「1,2,3,4」だとすると出力は以下のようになります。このコードだと文字列として格納されていますね。
['1', '2', '3', '4']
数値として取りたいときはさきほども出てきた map 関数を使ってこう書きます。
input_list = list(map(int, input().split(","))) print(input_list)
数値としてリストに格納されています。
[1, 2, 3, 4]
N行のデータの入力
おそらく実際の問題では、1行目でこれから何個の値が与えられるかを示すN、2行目以降でその個数分の値が与えられることが多いと思います。この場合はforでループさせます。
入力例:
3
aaaaa
bbbbbb
cccc
コード:
# Nをint型で取得する N = int(input()) # 値を格納するリストを作る str_list = [] # str_listリストに取得したN個の値を格納する for i in range(N): str_list.append(input()) # str_listリストの中身を出力 print(str_list)
出力結果:
['aaaaa', 'bbbbbb', 'cccc']
プログラミング学習を始めたばかりのころは、上記の書き方が分かりやすいと思います。慣れてきたら次に示す内包表記で書いてみましょう。
# Nをint型で取得する N = int(input()) # 内包表記でstr_listリストに値を格納する str_list = [input() for i in range(N)] # str_listリストの中身を出力 print(str_list)
値の与えらるパターンはいろいろありますが、ここまでお伝えしてきた内容を理解できていれば、少しの応用で対応できると思います。
理解度チェックには問題集の「標準入力セット」を解いてみてください。
問題文を正しく把握する
paizaのスキルチェックというサービスでは、プログラミング問題の難易度を高い順にS・A・B・C・Dに分けています。問題集でも難易度の分け方は同様で、今回はDランク相当の問題を解いていきます。
問題内容:
騒音値は、デシベル(dB)という単位で表され、騒音値の大きさで、騒音の大きさが判断されます。
~ 30 dB : 静か
30 ~ 50 dB : 普通
50 ~ 70 dB : うるさい
70 ~ dB : とてもうるさい入力として騒音値(dB)が与えられるので、騒音の大きさがどれほどであるのかを出力してください。
入力値:
入力は以下のフォーマットで与えられます
l
lは騒音値を表す自然数
期待する出力:
l < 30 のとき、 quiet
30 ≤ l < 50 のとき、normal
50 ≤ l < 70 のとき、noisy
70 ≤ l のとき、 very noisy
を出力してください。
条件:
すべてのテストケースにおいて、以下の条件をみたします。
10 ≤ l ≤ 120
問題文を見て「簡単過ぎる!」と思った方もいるかも知れません。
確かに難易度は高くありませんが、実は油断すると間違えやすいポイントが詰まっている問題なんです。この問題で気をつけないといけないのは「境界値がどちらの出力になるか」です。
パッと見ただけだと30、50、70のときの出力結果を間違える可能性があります。
そこで期待する出力の内容に入力値の条件を加味してもう少し噛み砕いてみると…
l が10から29のときは「quiet」を出力
l が30から49のときは「normal」を出力
l が50から69のときは「noisy」を出力
l が70から120のときは「very noisy」を出力
これでだいぶ分かりやすくなりました。
短時間で解くことを目指すには、「何を問われているか」を正確に把握する必要があります。最初のうちは理解しやすいように自分なりに言い換えたり、書き換えたりしてみるとよいでしょう。
入出力について考える
問題内容の把握ができたので、次は実際の入力値に対してどのように処理するべきかを考えていきます。
入力例だけを通せばいいわけではない
この問題では入力例が2つ与えられています。
入力例1
36出力例1
normal
入力例2
80出力例2
very noisy
とにかく「36」が与えられたら「normal」、「80」が与えられたら「very noisy」が出力されればよさそうですね。
このときプログラミング初心者の方からよくお聞きするお悩みで「入力例は通ったのに提出すると他のテストケースが通らずどうしようもなくなってしまった」というのがあります。
ものすごく極端な話をしますが、「入力例が通ればいい」と考えると以下のコードでもよいことになります。
# 騒音値を取得する dB = int(input()) # 36のときnormal、80のときvery noisyを出力 if(dB == 36): print("normal") elif(dB == 80): print("very noisy")
下の画像は提出前動作確認をしたときのスクリーンショットですが「実行結果ステータス: Success」となっていますよね。
しかし、提出してみると当然テスト3は失敗し、以降全てテストはスキップされました。
もちろん今回は与えられる値が1つで、かつ条件も単純なので、こんな考え方はしないと分かるのですが、問題の難易度に限らず「入力される値は1つ、2つではなく条件に示された範囲で変化する」ということは頭に入れておく必要があります。
テストケースの考え方
今回の問題では、入力例1と2の他にどんな値をテストケースとして試せばよいでしょうか。
実務でも必ず試験をするのが入力値の「境界値」です。その名の通り境界にある値、つまり出力結果が変わる前後の値です。そして、もうひとつは条件の「最小値」「最大値」です。
ここで最初に書き出した以下が役に立ちます。
l が10から29のときは「quiet」を出力
l が30から49のときは「normal」を出力
l が50から69のときは「noisy」を出力
l が70から120のときは「very noisy」を出力
入力値10、29、30、36、49、50、69、70、80、120すべてで想定した出力結果になればほぼ正しいコードであると言ってよいと思います。
(本当は「出力結果が変わる前後の値」なので28、31もテストすべきではと思うのですが今回は省略します。難しい問題の場合はやったほうがいいです)
冒頭でご紹介したpaiza.IOを使って、入力値は自由に変えて試すことが可能です。当然ですが、さきほどのコードでは正しい結果にはなりません。ためしに、入力値10で実行してみます。
実行ボタンをクリックすると……
エラーにはなりませんが何も出力されませんでした。
paizaで公開しているプログラミング問題では条件範囲外の値が与えられることはないため、このコードでもエラーは発生しません。たとえば、今回の問題で l にマイナスの値が入ってきたり、文字列が入ってきたりすることはないという前提で問題を解いて大丈夫です。
しかし現実には意図しない値が入力される可能性があるので、例外処理を実装しておきます。例外処理については「Python入門編10: 例外処理を理解しよう」で学べます。
ちなみにテストケースの考え方をもっと詳しく知りたい方は、以下の記事も参考にしてみてください。
コードを書く
ここまで内容を正しく理解し、与えられた値に対してどんな結果が出力されればいいかを整理できたのであとはコードを書いていきます。
# 騒音値を取得する dB = int(input()) # l が10から29のときは「quiet」を出力 if(10 <= dB <= 29): print("quiet") # l が30から49のときは「normal」を出力 elif(30 <= dB <= 49): print("normal") # l が50から69のときは「noisy」を出力 elif(50 <= dB <= 69): print("noisy") # l が70から120のときは「very noisy」を出力 elif(70 <= dB <= 120): print("very noisy")
コードを書いたあとは「境界値」「最小値」「最大値」そして入力例1、2でテストしてみてくださいね。
すべて正しい出力になったことを確認できたら、問題集のほうで提出してみましょう。
すべてのテストケースに通り、100点を獲得しました!
ところで今回は上記のようにifの条件を分けましたが、以下のようにしても構いません。プログラムの正解はひとつではないのでご自分が理解しやすい考え方で解いてください。
# 騒音値を取得する dB = int(input()) # l が30未満のときは「quiet」を出力 if(dB < 30): print("quiet") # l が30以上50未満のときは「normal」を出力 elif(30 <= dB < 50): print("normal") # l が50以上70未満のときは「noisy」を出力 elif(50 <= dB < 70): print("noisy") # l が70以上のときは「very noisy」を出力 elif(70 <= dB): print("very noisy")
ここまでお伝えしてきたことはpaizaラーニングの講座「特別編: 初めてのスキルチェック」で動画で分かりやすく解説していますのでぜひチェックしてみてください。
(応用)複数の入力値が与えられる問題だったら
今回は与えられる値(dB)は1つだったので、if文だけを使ってうまく処理することができました。
もし「条件:10 ≤ l ≤ 120」の範囲内で5つの値が、カンマ区切りで与えられ、それぞれに対して結果を改行して出力する問題だったらどのようにコードを書けばよいでしょうか。
入力例
12,70,107,42,67出力例
quiet
very noisy
very noisy
normal
noisy
まずは値を取得して、リストに入れる処理を書きます。数値で取得したいのでmap関数を使います。
dB_list = list(map(int, input().split(","))) print(dB_list)
出力結果:
[12, 70, 107, 42, 67]
次にリストにある値を1つずつ判定するためにfor文を使います。dB_list[リスト内の何番目かを指定する添字] と書くことでリストの値を1つ取り出せます。
dB_listの長さ(格納された値の数)は len(dB_list) で取得できるので、それをfor文の終了条件とします。この場合、len(dB_list)は「5」ですね。
添字iは「0」からはじまり「5」未満で終了なので、dB_listに格納された値をi = 0(1つ目の値)、i = 1(2つ目の値)、i = 2(3つ目の値)、i = 3(4つ目の値)、i = 4(5つ目の値)ですべて判定できます。
# リストに与えられる値を格納する dB_list = list(map(int, input().split(","))) # リストの値を1つずつ判定して結果を出力する for i in range(len(dB_list)): # l が10から29のときは「quiet」を出力 if(10 <= dB_list[i] <= 29): print("quiet") # l が30から49のときは「normal」を出力 elif(30 <= dB_list[i] <= 49): print("normal") # l が50から69のときは「noisy」を出力 elif(50 <= dB_list[i] <= 69): print("noisy") # l が70から120のときは「very noisy」を出力 elif(70 <= dB_list[i] <= 120): print("very noisy")
出力結果:
quiet
very noisy
very noisy
normal
noisy
想定した出力になりました!
ここで終わりでもいいのですが、もう少しテストをしておきましょう。
入力値を考えるのがちょっと面倒なので、条件の範囲内で5つの値をランダムで生成する処理を加えます。
import random # ランダム関数で10以上121未満のランダムな整数を5つ持つリストを作る dB_list = [random.randrange(10, 121) for i in range(5)] print("生成されたランダムな値を確認:", end="") print(dB_list) # リストの値を1つずつ判定して結果を出力する for i in range(len(dB_list)): # l が10から29のときは「quiet」を出力 if(10 <= dB_list[i] <= 29): print("quiet") # l が30から49のときは「normal」を出力 elif(30 <= dB_list[i] <= 49): print("normal") # l が50から69のときは「noisy」を出力 elif(50 <= dB_list[i] <= 69): print("noisy") # l が70から120のときは「very noisy」を出力 elif(70 <= dB_list[i] <= 120): print("very noisy")
出力結果:
生成されたランダムな値を確認:[58, 83, 12, 51, 88]
noisy
very noisy
quiet
noisy
very noisy
正しく出力できていますね。Dランク相当の問題でここまでやるべきかと言うと、時間もかかりますしおそらく無駄もあるかもしれません。
ただ、このようにテストをしてミスを減らすという考え方は難易度が高い問題にチャレンジするときに役立つはずです。
(コラム)Pythonの文字列処理
今回の問題では文字列を扱わなかったので、ここでPythonの文字列処理について少し説明します。
初心者にとって初期の学習コストが低い言語と高い言語の差は何かを考えたときに、文字列の扱いやすさがひとつの理由になると思います。
Pythonは文字列が扱いやすく、たとえば取得した文字列をそのまま出力することはもちろん
word = "Hello Paiza!" print(word)
出力結果:
Hello Paiza!
リストのように一文字ずつ出力する処理も簡単に書けます。
word = "Hello Paiza!" print(word[0]) print(word[6])
出力結果:
H
P
また、何文字目から何文字分取得するというのもこのように書くことができます。
word = "Hello Paiza!" # 7文字目から11文字目まで出力(0からスタートのため) print(word[6:11])
出力結果:
Paiza
これを「スライス」といい、文字列を処理するプログラム問題を解く際はよく使うので覚えておきましょう。(もっといろんな使い方があるので、興味がある方は検索してみてください。)
Python以外の言語も書き方に多少差はあれど、このような処理ができることを知っていると文字列を扱う問題は格段に解きやすくなります。
ちなみに同じことをC言語でやろうとすると結構大変です。同じ問題を解く場合でも言語によって難易度に違いがあるという話は別の機会でお伝えしたいと思います。
まとめ
練習問題を使って、標準入力の処理から始まり実際に問題にどのように取り組むかをお伝えしてきました。
プログラミング学習を始めたばかりのころは、問題を解くための方針を立てることもなかなか難しいと思いますが、今回やってみたように少していねいに問題の理解やテストケースの検討などをして解くと慣れてきますので頑張りましょう!
慣れてきたら時間制限があり、解答時間などによってスコアが算出されるスキルチェックの本問題にもチャレンジして腕試しをしてみてください。
また、paizaではゲーム感覚で学習ができるコンテンツもご用意していますので、「ただ問題を解くだけは疲れた…癒やしが欲しい…」という方はのぞいてみてください。
基礎文法の習得からという方には、ファンタジー系RPGのような世界観でプログラミング問題を解きながら物語を進めていく『コードクロニクル』がおすすめです。
「paizaラーニング」では、未経験者でもブラウザさえあれば、今すぐプログラミングの基礎が動画で学べるレッスンを多数公開しております。
詳しくはこちら
そしてpaizaでは、Webサービス開発企業などで求められるコーディング力や、テストケースを想定する力などが問われるプログラミングスキルチェック問題も提供しています。
スキルチェックに挑戦した人は、その結果によってS・A・B・C・D・Eの6段階のランクを取得できます。必要なスキルランクを取得すれば、書類選考なしで企業の求人に応募することも可能です。「自分のプログラミングスキルを客観的に知りたい」「スキルを使って転職したい」という方は、ぜひチャレンジしてみてください。
詳しくはこちら