0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JOIのコーディングが楽になる考え方

0
Posted at

プログラミング学習中のみなさん、こんにちは!

今回は、日本情報オリンピック(JOI)の難易度4レベルまでの過去問を題材に、初心者でもスッキリ理解できる「プログラミング的思考法」を解説していきます!

JOIの問題を解くとき、こんな風に考えていませんか?

  • 「とりあえず結果を保存する配列を作らなきゃ…」
  • 「条件ごとにグループ分けして配列に分けて…」

実はそれ、コードを無駄に複雑にしている原因かもしれません!

今日は生徒のKくんと一緒に、「無駄な変数を作らず、シンプルに最短コードで解くコツ」を学んでいきましょう!

Gemini_Generated_Image_br8xidbr8xidbr8x.jpg

【第1問】文字の置き換え問題

【問題】
文字列の J を O に、O を I に、I を J に変換した後の文字列を出力してください。

Kくん:
「まずは文字列を1文字ずつ受け取って、配列(リスト)に格納してから変換していけばいいのかな?」

講師:
「おっ、処理の流れはバッチリ!でもね、“出力するためだけにわざわざ新しいリストを作る必要はない”んだよ。」

Kくん:
「えっ、リストを作らなくていいの?」

講師:
「 Pythonの文字列は for 文でそのまま1文字ずつ取り出せるんだ。取り出した文字をその場で判定して、改行なしで出力しちゃえばOK!Python 3.10以降なら match-case を使うとスッキリ書けるよ。」

💡 講師の模範コード(Python)

N = int(input())
S = input()

for char in S:
    match char:
        case "J":
            print("O", end="")
        case "O":
            print("I", end="")
        case "I":
            print("J", end="")
print()  # 最後に改行

Kくん:
「配列を作らない分、コードも短くてメモリの無駄もないね!」

【第2問】2つの数列を交互に並べる問題

【問題】
長さ $N$ の整数列 $A = (A_1, A_2, \dots, A_N)$ と $B = (B_1, B_2, \dots, B_N)$ が与えられます。
$A$ と $B$ を交互に並べた長さ $2N$ の列 $C = (A_1, B_1, A_2, B_2, \dots, A_N, B_N)$ を出力してください。

Kくん:
「これは新しい配列 $C$ を作って、そこに $A_1, B_1, A_2, B_2\dots$ の順番で追加していけば完璧だよね!」

講師:
「ここでも思考のシンプル化が使えるよ!問題文に『列 $C$ を出力せよ』とあるけど、後から列 $C$ を再利用したり編集したりする指示はあるかな?」

Kくん:
「ううん、出力するだけだね。」

講師:
「だったら、配列 $C$ を作る時間もメモリも勿体ない! 繰り返し処理の中で、$A_i$ と $B_i$ をそのまま交互にプリントしちゃえばいいんだよ。」

💡 講師の模範コード(Python)

N = int(input())
A = list(map(int, input().split()))
B = list(map(int, input().split()))

for i in range(N):
    print(A[i])
    print(B[i])

Kくん:
「うわ、たったこれだけで終わっちゃった…!『出力するためだけの変数・配列は作らない』のがコツなんだね。」

【第3問】クラス分けとボーダーライン問題

【問題】
$N$ 人の生徒の点数が与えられます。ある点数 $x$ を基準にして、 $x$ 点以上を進学クラス、$x$ 点未満を普通クラスに分けます。

  • 両方のクラスに1人以上の生徒が属する
  • 進学クラスと普通クラスの人数差が最小になる
  • 条件を満たす分け方が複数ある場合、進学クラスの人数が最小になる分け方を選ぶ

このとき、進学クラスの最低点(=基準となる $x$)を求めてください。

Kくん:
「う〜ん、進学クラス用の配列と普通クラス用の配列を準備して、点数を比較しながら分けていけばいいのかな…?」

講師:
「今回求められている最終出力は何だっけ?」

Kくん:
「『進学クラスの最低点』だから、数字1個だけだ!」

講師:
「そう!数字1個を答えるだけだから、生徒を実際に別々の配列に振り分ける必要はないんだよ。」

Kくん:
「じゃあどうやって考えるの?」

講師:
「ポイントは次の3ステップ!

  1. 点数を降順(高い順)にソートする
  2. 人数が半分(二等分)になるあたりを基準に考える
  3. 同じ点数の生徒が境界線にまたがらないよう注意しながら、進学クラスの人数が少なくなるギリギリの点数を見つける」

💡 講師の模範コード(Python)

N = int(input())
A = list(map(int, input().split()))

# 点数を高い順(降順)に並べ替える
A.sort(reverse=True)

# 人数が均等になるインデックス(中央付近)から探す
half = N // 2

# 同じ点数の人が境界にいる場合は、進学クラス側を減らす方向(インデックスを前)へ調整
while half > 1 and A[half - 1] == A[half]:
    half -= 1

# 進学クラスの最低点を出力
print(A[half - 1])

Kくん:
「ソートしてから位置を計算するだけで求まるんだ!配列を2つ作ってループを回すより、ずっと見やすくてスマートだね。」

まとめ:競プロ・JOI攻略の3大原則

今回学んだ「コードをシンプルにする考え方」を振り返ってみましょう!

  • 原則1:無駄な変数は作らない(最終出力に必要なものだけ保持する)
  • 原則2:なるべくシンプルに考える(「配列に保存」ではなく「その場で処理」できないか疑う)
  • 原則3:なるべく短いコードで済ます(コードが短ければバグも減る!)

JOIなどの競技プログラミングでは、解法を思いついたあとに「これ、もっと簡単に書けないかな?」と一度立ち止まって考える癖をつけるのが上達の近道です。

みなさんもぜひ、無駄のないスッキリとしたコードを目指してみてくださいね!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?