Pythonの練習問題を解いてみよう!

実践

勉強は学んだことをアウトプットすることがとても大切です。

練習問題を解き、Pythonを「知っている」だけではなく「使える」ようになっているか、確かめてみましょう。

レベル1

FizzBuzz

1から100の数字を出力しなさい。ただし、3の倍数は数字の代わりに”Fizz”、5の倍数は数字の代わりに”Buzz”、3と5の倍数は数字の代わりに”FizzBuzz”を出力しなさい。ただし、「3と5の倍数」の条件は「3の倍数」または「5の倍数」よりも優先される。例えば、15は3の倍数であるが、5の倍数でもあるため”Fizz”とは出力せず、”FizzBuzz”と出力することになる。

for i in range(1, 101):
    if i % 3 == 0 and i % 5 == 0:
        print("FizzBuzz")
    elif i % 3 == 0:
        print("Fizz")
    elif i % 5 == 0:
        print("Buzz")
    else:
        print(i)

for文で1~100のループを作り、それぞれの数字について「3の倍数かつ5の倍数」かどうか、「3の倍数」かどうか、「5の倍数」かどうかを判定しています。

「3の倍数である」ということは、「3で割った余りが0である」ということですので、%演算子を使って判定しましょう。

掛け算九九

for文を使い、次に示す九九の表を出力しなさい。

  1  2  3  4  5  6  7  8  9
  2  4  6  8 10 12 14 16 18
  3  6  9 12 15 18 21 24 27
  4  8 12 16 20 24 28 32 36
  5 10 15 20 25 30 35 40 45
  6 12 18 24 30 36 42 48 54
  7 14 21 28 35 42 49 56 63
  8 16 24 32 40 48 56 64 72
  9 18 27 36 45 54 63 72 81
for x in range(1, 10):
    for y in range(1, 10):
        print(str(x * y).rjust(3), end="")
    print()

for文で二重ループを作り、積を計算しましょう。

        print(str(x * y).rjust(3), end="")

の部分は、str関数で整数を文字列に変換し、rjust関数で文字数を3に指定したうえで右寄せにします。

print関数の引数endは出力後の文字を示し、デフォルトでは改行文字となっていますが、今回は改行させたくないため空文字を指定しています。

中央値

3つの整数を入力から受け取り、その中央値を出力しなさい。以下の例では、”1 3 2″を入力として受け取り、その次の行で中央値の”2″を出力している。

$ python3 median.py 
1 3 2 
2
a, b, c = map(int, input().split()) 

if b <= a <= c or c <= a <= b:
    print(a)
elif a <= b <= c or c <= b <= a:
    print(b)
else:
    print(c)

Pythonでは、「aがb以上かつcがa以上」という条件は

b <= a <= c

のように続けて書くことができます。これを利用し、「aが中央値の場合」「bが中央値の場合」「それ以外の場合(=cが中央値の場合)」に場合分けして結果を出力しましょう。

レベル2

ファイル名整理

以下の形式のファイル名が改行区切りで20個与えられる。なお、「ゼロ埋め2桁番号」は01~10までの計10個が重複無く存在する。

<ゼロ埋め2桁番号>_<アルファベットからなる文字列>.<"csv"または"txt">

以下の形式で出力せよ。

--- txt files ---
01_<アルファベットからなる文字列>.txt
02_<アルファベットからなる文字列>.txt
03_<アルファベットからなる文字列>.txt
...
09_<アルファベットからなる文字列>.txt
10_<アルファベットからなる文字列>.txt
--- end of txt files ---

--- csv files ---
01_<アルファベットからなる文字列>.csv
02_<アルファベットからなる文字列>.csv
03_<アルファベットからなる文字列>.csv
...
09_<アルファベットからなる文字列>.csv
10_<アルファベットからなる文字列>.csv
--- end of csv files ---

入力例

03_alpha.csv
09_beta.txt
08_gamma.csv
05_delta.txt
01_epsilon.csv
04_zeta.txt
06_eta.csv
08_theta.txt
09_iota.csv
02_kappa.txt
05_lambda.csv
07_mu.txt
02_nu.csv
10_xi.txt
07_omicron.csv
06_pi.txt
10_rho.csv
03_sigma.txt
04_tau.csv
01_upsilon.txt

出力例

--- txt files ---
01_upsilon.txt
02_kappa.txt
03_sigma.txt
04_zeta.txt
05_delta.txt
06_pi.txt
07_mu.txt
08_theta.txt
09_beta.txt
10_xi.txt
--- end of txt files ---

--- csv files ---
01_epsilon.csv
02_nu.csv
03_alpha.csv
04_tau.csv
05_lambda.csv
06_eta.csv
07_omicron.csv
08_gamma.csv
09_iota.csv
10_rho.csv
--- end of csv files ---
files = [input() for _ in range(20)]

txt_files = []
csv_files = []

for filename in files:
    if filename.endswith(".txt"):
        txt_files.append(filename)
    elif filename.endswith(".csv"):
        csv_files.append(filename)

txt_files.sort()
csv_files.sort()

print("--- txt files ---")
for filename in txt_files:
    print(filename)
print("--- end of txt files ---")
print()
print("--- csv files ---")
for filename in csv_files:
    print(filename)
print("--- end of csv files ---")

入力からファイル名を取得し、txt用のリストとcsv用のリストにそれぞれ該当するファイル名を追加しています。

文字列sが特定の文字列tで終わるかどうかは、

s.endswith(t)

で判定することができます。sがtで終わる場合はTrue、終わらない場合はFalseを返します。

その後はリストのsortメソッドでファイル名を昇順にソートし、出力しています。

山手線2駅間の距離

山手線の駅2つを入力で受け取り、内回りの場合の2駅間の距離[m]を求めよ。

入力はスペース区切りとする。

各駅の名称、各駅間の距離は以下のディクショナリを参照すること。キーが駅名、値が内回りにおける直前の駅からの距離[m]である。例えば、御徒町駅から上野駅までの距離は600mである。

stations = {
    "神田駅": 1300,
    "秋葉原駅": 700,
    "御徒町駅": 1000,
    "上野駅": 600,
    "鶯谷駅": 1100,
    "日暮里駅": 1100,
    "西日暮里駅": 500,
    "田端駅": 800,
    "駒込駅": 1600,
    "巣鴨駅": 700,
    "大塚駅": 1100,
    "池袋駅": 1800,
    "目白駅": 1200,
    "高田馬場駅": 900,
    "新大久保駅": 1400,
    "新宿駅": 1300,
    "代々木駅": 700,
    "原宿駅": 1500,
    "渋谷駅": 1200,
    "恵比寿駅": 1600,
    "目黒駅": 1500,
    "五反田駅": 1200,
    "大崎駅": 900,
    "品川駅": 2000,
    "高輪ゲートウェイ駅": 900,
    "田町駅": 1300,
    "浜松町駅": 1500,
    "新橋駅": 1200,
    "有楽町駅": 1100,
    "東京駅": 800
}

参考:山手線 – Wikipedia

入力例

目黒駅 浜松町駅

出力例

7800
# 各駅の名称と、内回りにおける直前の駅からの距離[m]
stations = {
    "神田駅": 1300,
    "秋葉原駅": 700,
    "御徒町駅": 1000,
    "上野駅": 600,
    "鶯谷駅": 1100,
    "日暮里駅": 1100,
    "西日暮里駅": 500,
    "田端駅": 800,
    "駒込駅": 1600,
    "巣鴨駅": 700,
    "大塚駅": 1100,
    "池袋駅": 1800,
    "目白駅": 1200,
    "高田馬場駅": 900,
    "新大久保駅": 1400,
    "新宿駅": 1300,
    "代々木駅": 700,
    "原宿駅": 1500,
    "渋谷駅": 1200,
    "恵比寿駅": 1600,
    "目黒駅": 1500,
    "五反田駅": 1200,
    "大崎駅": 900,
    "品川駅": 2000,
    "高輪ゲートウェイ駅": 900,
    "田町駅": 1300,
    "浜松町駅": 1500,
    "新橋駅": 1200,
    "有楽町駅": 1100,
    "東京駅": 800
}

# 累積和を計算
cumulative_sum = {}
temp_sum = 0
for station_name, distance in stations.items():
    temp_sum += distance
    cumulative_sum[station_name] = temp_sum

# 入力
station_from, station_to = input().split()

# 出力
ans = cumulative_sum[station_to] - cumulative_sum[station_from]
if ans < 0:
    ans += cumulative_sum["東京駅"]

print(ans)

この問題は累積和を使うことでシンプルに解くことができます。

変数cumulative_sumに内回りにおける直前の駅からの距離の累積和、つまり東京駅からの距離を代入することで、その差を計算して駅間の距離を求めることができます。

もし求めた距離ansがマイナスとなった場合は、ansに「-(2駅間の外回りにおける距離)」が入っているため、「山手線一周の距離(=東京駅から東京駅まで一周した距離であるcumulative_sum[“東京駅”])」にansを加えることで、求めたい距離を計算できます。

レベル3

経路の数

ある建物には部屋が10個ある。それぞれ部屋1、部屋2、部屋3、…、部屋10と呼ぶことにする。

それぞれの部屋からは、以下の通り特定の1つ以上の部屋に通路で直接つながっている。例えば、部屋1は部屋2と部屋5の2つの部屋と通路で直接つながっており、行き来ができる。

部屋つながっている部屋
部屋1部屋2、部屋5
部屋2部屋1、部屋6、部屋8
部屋3部屋4、部屋7
部屋4部屋3、部屋7、部屋10
部屋5部屋1、部屋8
部屋6部屋2、部屋8、部屋9
部屋7部屋3、部屋4
部屋8部屋2、部屋5、部屋6
部屋9部屋6、部屋10
部屋10部屋4、部屋9

上記に加え、部屋2と部屋3、部屋6と部屋7、部屋8と部屋9は日本時間で9:00~17:00の間のみ通行ができ、0:00から9:00になる直前、17:00の直後から24:00の間は封鎖されている。(つまり、9:00ちょうどと17:00ちょうど、及びその間は通行が可能である。)

現在の時間を取得し、その時間における部屋1から部屋10までの全経路を出力しなさい。例えば、部屋1→部屋2→部屋6→部屋9→部屋10の経路は以下のように出力する。

1 2 6 9 10

また、最後の行に全経路数を出力しなさい。

ただし、一度通った部屋をもう一度通ることはできないものとする。(例えば、部屋1→部屋2→部屋6→部屋8→部屋2→部屋3→部屋4→部屋10という経路は部屋2を2回通っているため不可であり、1経路としてカウントされない。)

import datetime

# 日本標準時で時刻を取得
JST = datetime.timezone(datetime.timedelta(hours=+9), "JST")
t_now_jst = str(datetime.datetime.now(JST).timetz())

# keyは部屋番後
# valueはkeyの部屋からつながっている部屋のリスト
g = {
    1: [2, 5],
    2: [1, 6, 8],
    3: [4, 7],
    4: [3, 7, 10],
    5: [1, 8],
    6: [2, 8, 9],
    7: [3, 4],
    8: [2, 5, 6],
    9: [6, 10],
    10: [4, 9]
}

# 現在時刻が9:00~17:00の間であれば
# 部屋2と部屋3、部屋6と部屋7、部屋8と部屋9をつなぐ
if "09:00:00.000000+09:00" <= t_now_jst <= "17:00:00.000000+09:00":
    g[2].append(3)
    g[3].append(2)
    g[6].append(7)
    g[7].append(6)
    g[8].append(9)
    g[9].append(8)

# 部屋iまでの経路数を求める関数
# visitedは訪問済みの部屋番号のリスト
def calc(i, visited=[]):
    if i == 1:
        print(*([1] + visited))
        return 1
    ans = 0
    for prev in g[i]:
        if not prev in visited:
            ans += calc(prev, [i] + visited)
    return ans

print(calc(10))

最初に現在時刻(日本時間)を取得し、その次に部屋同士のつながりをディクショナリgで表現します。

部屋iまでの経路数を求める再帰関数calcを定義し、最後に部屋10までの経路数を求めます。

タイトルとURLをコピーしました