Pixabayからの画像
こんにちは。倉内です。
さまざまなプログラミング学習サービスのおかげで、プログラミングを始めるハードルはとても低くなりました。特に入門的な内容は無料で学べることも多いため、やり始めはある程度スムーズに進められるという人も多いでしょう。
ただ、「なんとなく分かった気はするが、初心者から先になかなかレベルアップできない」「基礎文法を学んで、次に何を学べばいいか分からない」という方もよくお見かけします。
作りたいサービスのイメージができている場合でも「それをどのような方法で実現するか」を考え、試行してみるというプロセスは実際に手を動かして身につけていく必要があります。
そこで今回は、paizaで公開しているプログラミング問題を解きながら、自分でコードを書く力をつけるための方法をお伝えできればと思います。
自分のプログラミングスキルを測る
本題に入る前に「自分は今どのくらいプログラミング問題が解けるだろうか?」というのを測ってみたい方にpaizaのスキルチェックを紹介します。
スキルチェックでは、問題の難易度がS・A・B・C・Dのランクに分かれており、基礎文法を習得できていれば解けるDランクから、問題文を正確に読み解き採用すべきアルゴリズムや大規模データのテストケースを考慮する必要があるSランクまでさまざまな問題をご用意しています。
スキルチェックについて詳しくはこちら
この中では、Cランクが脱初心者をするにはちょうどいいレベルになっていますので、今回はCランク問題の解き方をお伝えしていきます。
スキルチェックの問題はpaizaが提供している就職・転職サービスの求人応募に関係するため、解説や解答を公開することはご遠慮いただいています。
そのため今回は、ゲームイベントで公開しているプログラミング問題を使います。こちらはコードを公開したり友人に聞いて解いたりしても構いませんので学習にぜひご利用ください。
Cランク相当の問題解説
『エンジニアが死滅シタ世界』というゲームイベントにCランク相当の問題があるので、そのうちの2問をPythonで解いてみます。解答コードは以前公開してるので、それだけ見たい方はこちらへ。(解き方はひとつではないのであくまで解答例と思ってください)
ちなみに問題を解くとアンドロイドのRINちゃんの着せかえ衣装などがゲットできます。
書いたコードはゲーム内で提出し、CLEARまたはFAILEDの判定がされます。
機械の総合病院 [MISSION LEVEL: C]
PAIZA病院のシステムを解析します。
不正アクセスを試みるクラッカーからユーザーを守るために、ユーザーが設定するパスワードが十分に複雑であるようにしなくてはなりません。
PAIZA病院は、パスワードの複雑さの条件として以下の 3 つを定めました。・長さが 6 以上
・英字と数字の両方を含む必要がある
・同じ文字を 3 つ以上連続で使用することはできないなお、英字の大文字と小文字は区別する必要はありません。
パスワードの候補が入力として与えられるので、複雑さの条件をすべて満たす場合は "Valid"、そうでない場合は "Invalid" と出力してください。例えば、入力例 1 で与えられる 7Caaad9 は 1 つ目の条件と 2 つ目の条件を満たしますが、aaa と 3 つ以上同じ文字が連続で使用されているため、複雑さの条件をすべて満たしません。
入力される値:
t
・パスワードの候補となる文字列 t が与えられます。
・入力は 1 行となり、末尾に改行が 1 つ入ります。
条件:
・1 ≦ (t の長さ) ≦ 30
・文字列 t は半角英字あるいは半角数字で構成された文字列
考え方:
問題文が結構長くて一瞬ひるみますが、いきなりコードは書かず全体の方針を立てましょう。
パスワード候補の文字列を「password」という変数で受け取る。
条件①長さが6以上かを判定
OKなら次の条件判定へ
NGなら“Invalid”を出力条件②英字と数字の両方を含んでいるかを判定
メモ:数字は全部で10、英字は全部で26、どちらも1つずつ入っているかを調べる?もしくは正規表現を使う?ただし、大文字・小文字の区別は不要OKなら次の条件判定へ
NGなら“Invalid”を出力条件③同じ文字が 3 つ以上連続で使用されていないかを判定
メモ:passwordを先頭から順に見て自身・次の文字・その次の文字で3連続していないかをサーチする?NGなら“Invalid”を出力
条件①~③を満たしていれば“Valid”を出力
コードを書く:
さきほど書き出した内容を上から順にコードにしていきます。
まずは標準入力で文字列を受け取る処理を書きましょう。Pythonの標準入力は「Python3入門編」の講座「#05:データの読み込み(標準入力)」で解説しています。
password = input()
Pythonではinput関数を使って与えられた値を取得できます。
つづいて「条件①長さが6以上かを判定」する処理を書きます。NGだったら=6より短かったら“Invalid”を出力するという処理にしましょう。文字列の長さを取るにはlen関数を使います。
if len(password) < 6: print("Invalid")
ここまでは大丈夫ですね。次の「条件②英字と数字の両方を含んでいるかを判定」が少しやっかいです。ここでは、さきほど書いたメモのとおり「数字は全部で10、英字は全部で26、どちらも1つずつ入っているかを調べる」で実装してみることにします。
要はパスワード候補の文字列(password)に0~9の数字と一致した文字がある、かつ、A~Zの英字と一致した文字がある場合はOKということです。
どの文字が入っているか判断する必要はないので(どれでも1つずつ入っていればOK)False、Trueのフラグを使います。
# サーチするために数字と英字を定義 numbers = "0123456789" alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIGJKLMNOPQRSTUVWXYZ" # 数字と英字があるかのフラグ(デフォルトはFalse(なし)) num = False alpha = False # passwordを先頭から順に一致するか判定 for i in password: # 英字が含まれるか(含まれていたらTrue(あり)) if i in alphabet: alpha = True # 数字が含まれるか(含まれていたらTrue(あり)) if i in numbers: num = True # どちらかがFalseなら“Invalid” if alpha == False or num == False: print("Invalid")
最後に「条件③同じ文字が 3 つ以上連続で使用されていないかを判定」する処理を書きましょう。
メモに書いたとおり、passwordを1文字ずつ先頭から順に見て、自身・次の文字・その次の文字…で3つ以上連続していたらNGとします。
# 連続しているか数えるための変数 cnt = 1 # 連続しているか数える文字を一時的に入れる変数 tmp = '' # passwordを1文字ずつ先頭から順に見て、3つ以上連続しているか判定 for i in password: # 一致していたらカウントアップ if tmp == i: cnt += 1 # cntが3以上=3文字以上連続したら“Invalid” if cnt >= 3: print("Invalid") # 一致していなかったらcntを1にリセット else: cnt = 1 tmp = i
すべての条件を満たす処理を書くことができました。最後にすべて合わせたコードでテストしてみましょう。
このとき1つでも条件がNGの場合、“Invalid”と出力して処理を終了するため、プログラムを終了させるexit()を追加します。
# input関数で与えられた文字列を取得しpasswordに格納 password = input() # 文字列の長さが6以上かを判定 if len(password) < 6: print("Invalid") exit() # サーチするために数字と英字を定義 numbers = "0123456789" alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIGJKLMNOPQRSTUVWXYZ" # 数字と英字があるかのフラグ(デフォルトはFalse(なし)) num = False alpha = False # passwordを先頭から順に一致するか判定 for i in password: # 英字が含まれるか(含まれていたらTrue(あり)) if i in alphabet: alpha = True # 数字が含まれるか(含まれていたらTrue(あり)) if i in numbers: num = True # どちらかがFalseなら“Invalid” if alpha == False or num == False: print("Invalid") exit() # 連続しているか数えるための変数 cnt = 1 # 連続しているか数える文字を一時的に入れる変数 tmp = '' # passwordを1文字ずつ先頭から順に見て、3つ以上連続しているか判定 for i in password: # 一致していたらカウントアップ if tmp == i: cnt += 1 # cntが3以上=3文字以上連続したら“Invalid” if cnt >= 3: print("Invalid") exit() # 一致していなかったらcntを1にリセット else: cnt = 1 tmp = i # すべての条件がOKだったら“Valid”を出力 print("Valid")
このコードを提出してみると……
無事にクリアしてアイテム「ニットセーター」を手に入れました。ただ、ところどころ冗長な部分もあるので冒頭でお伝えした解答コードも見ておきましょう。
少し条件判定の順番が異なりますが、方針としては同じことをやっています。
password = input() if len(password) < 6: #6文字以上の条件外 print("Invalid") exit() numbers = "0123456789" alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIGJKLMNOPQRSTUVWXYZ" cnt = 1 num = False alpha = False tmp = '' for i in password: if tmp == i: cnt += 1 if cnt >= 3: #3文字以上連続する場合 print("Invalid") exit() else: cnt = 1 tmp = i if i in alphabet: alpha = True if i in numbers: num = True if alpha and num: print("Valid") else: print("Invalid")
大きく違うのはこの処理ですね。
if alpha and num: print("Valid")
上の解説では「どちらかがFalseなら“Invalid”」としたのですが、こちらではこの条件の判定を最後に持ってきて「どちらもTrueなら“Valid”」としています。
この問題はCランク相当の中でもやや難しめなので、これが解けたら自信を持ってもいいと思います。
荒れ果てたショップ [MISSION LEVEL: C]
あなたは今ファイルの管理をしようとしています。
各ファイルは番号で管理されていますが、一目でどの番号かわかるように、番号の左に適当な数の 0 を埋め込んで、番号の長さを固定することにしました。例えば、番号の長さを 3 で固定したい場合、0 は 000, 4 は 004, 13 は 013, 144 は 144 というようにファイル番号をつけます。
3 つの整数 N, A, B が与えられます。
A 以上 B 以下の数それぞれについて、番号の長さが N にするようなゼロ埋めをするとファイル番号はどのように表示されるかを出力してください。例えば、入力例 1:3 9 11 を説明する図は以下のようになります。
この例では、9, 10, 11 の 3 つの数を、すべて長さ 3 の番号にするために左に 0 を埋めることを考えます。
・9 は 1 桁の数なので、長さ 3 の番号にするには、2 つの 0 を左から埋める必要があります。
・10, 11 は 2 桁の数なので、長さ 3 の番号にするには、1 つの 0 を左から埋める必要があります。
入力される値:
N A B
・番号の長さを表す整数 N、表示したい番号の区間を表す整数 A, B がこの順に半角スペース区切りで与えられます。
・入力は 1 行となり、末尾に改行が 1 つ入ります。
条件:
・1 ≦ N ≦ 9
・0 ≦ A ≦ B ≦ 5000
・(B の桁数) ≦ N
考え方:
この問題はシンプルで、数字を指定された桁数にゼロ埋めするというものです。
一行でスペース区切りの3つの数字が渡されるので、それを受け取る標準入力の書き方から見ていきます。
コードを書く:
split()で区切った値をmap関数を使ってそれぞれの変数に格納できるため以下のようにシンプルなコードになります。(もしコンマ(,)区切りだったらsplit(",")で分割できます)
n, a, b = map(int, input().split())
この書き方はスキルチェック問題を解く際にひんぱんに使うので覚えてしまいましょう。
実はこの問題、解答例としては以下のコードを公開していました。
n, a, b = map(int, input().split()) for i in range(a, b+1): print(format(i, '0>'+str(n)))
ここで使われているformat関数を知っているとこんなにスマートに書くことができるんですね。
ただ、プログラミング学習を始めて間もないころはちょっと理解しにくいかなと思いますので、もうひとつzfillという文字列(str型)のメソッドを使った方法も紹介しておきます。
まず、開始の値から終了の値までをリストnum_listに入れます。
# 開始(a)~終了(b)までの値をリストにいれる num_list = [] for i in range(b - a + 1): num_list.append(a + i)
入力例1:3 9 11のとき、このnum_listには以下の値が格納されます。
[9, 10, 11]
このあとnが3なので、「009 010 011」とゼロ埋めをする処理を書く必要があることが分かります。
ここでzfillを使ってみましょう。
# num_listの値をn桁になるようゼロ埋めする for j in range(len(num_list)): print(str(num_list[j]).zfill(n))
書いたコードをすべて合わせて提出してみます。
# nはゼロ埋め後の桁数、aは開始の値、bは終了の値 n, a, b = map(int, input().split()) # 開始~終了までの値をリストにいれる num_list = [] for i in range(b - a + 1): num_list.append(a + i) # num_listの値をn桁になるようゼロ埋めする for j in range(len(num_list)): print(str(num_list[j]).zfill(n))
無事にクリアできました!
どちらの解き方も知っていないと使えませんが、「Python ゼロ埋め」「Python 桁をそろえる」などで検索してみるとすぐ目的にたどり着けると思います。
このあとの学習法について
Cランク問題を解いてみてどうでしたか?「ちょっと難しかったな…」と感じた方は、paizaラーニングが提供している「Cランクレベルアップセット」という練習問題集を活用してみてください。
この問題集は、Dランク問題をたくさん解くことでCランク問題を解けるようになるという目的で作ってあるので、無理なく力をつけていくことができます。現在はPython3のみ解答コードをご用意しています。
逆に「Cランク問題は簡単だった!」という方は、今度はBランク以上の問題に挑戦してみましょう。
同じく練習問題集「Bランクレベルアップセット」も提供していますのでまずはそちらでBランク問題がどのようなレベル感か試してみてください。
こちらはJava、Ruby、Python3、C#の解答コードを参照できます。
ちなみにAmazonギフト券が当たるキャンペーン問題の3週目はBランク問題ですので、スタートしたらぜひ挑戦してみてくださいね。
まとめ
paizaがゲームインベントとして公開している、Cランク相当の問題を一緒に解いてきました。
Dランクの問題に比べると多少問題文や条件が複雑になっているためCランク問題に手を出すのをためらう方もいるかもしれませんが、ひとつひとつ読み解いてみると意外に知っている知識の組み合わせでできる内容だったりします。
もちろん慣れも必要なので、ゲームイベントやレベルアップ問題集も活用してたくさん問題を解いて力をつけていきましょう!
そして力がついてきたなと思ったら冒頭でも紹介した「スキルチェック」で高ランクの問題に挑戦してみてください。
これからプログラミング学習を始めたいという方には、paizaラーニングがおすすめです。Python、Java、C言語、C#、PHP、Ruby、SQL、JavaScript、HTML/CSSなど、プログラミング未経験者や初心者でも動画で学べる入門レッスンを公開しています。
「Python入門編」「C#入門編」「ITエンジニアの就活準備編」といった人気講座も完全無料となっておりますので、プログラミングを学びたい方・ITエンジニアを目指したい方はぜひごらんください。
詳しくはこちら