🔙
🔝

【paiza問題集 解説】
配列活用メニュー

【配列を参照する操作】全ての要素に対する操作

【配列を参照する操作】全ての要素に対する操作

STEP: 1 指定の要素のカウント

指定の要素のカウント

    _, K = map(int, input().split())
    A = list(map(int, input().split()))
    print(a.count(K))
    

    リストの中の値の数を数える時は.count()メソッドを使います。「配列メニュー」の問題を終えた方なら楽勝だったことでしょう。👍

STEP: 2 全ての要素の和

全ての要素の和

    _ = int(input())
    A = list(map(int, input().split()))
    print(sum(a))
    

    リストの総和を求める時にはsum()関数を使います。リスト型変数を1つ引数として与えるだけで数値を全て足し算してくれます。

STEP: 3 配列の最大値

STEP: 3 配列の最大値

    _ = int(input())
    A = list(map(int, input().split()))
    print(max(a))
    

    リストの中から最大値を見つける時はmax()関数を使います。

STEP: 4 配列の最小値

配列の最小値

    _ = int(input())
    A = list(map(int, input().split()))
    print(min(a))
    

    リストの中から最小値を見つける時はmin()関数を使います。

STEP: 5 指定要素があるかの判定

指定要素があるかの判定

  • 例1

  • _, K = map(int, input().split())
    A = list(map(int, input().split()))
    
    if K in A:
        print('Yes')
    else:
        print('No')
    
  • 例2

  • _, K = map(int, input().split())
    A = list(map(int, input().split()))
    print('Yes' if K in A else 'No')
    

    リストの中から特定の値を探す時はin を使います。

STEP: 6 指定要素の先頭位置

指定要素の先頭位置

  • 例1

  • _, K = map(int, input().split())
    A = list(map(int, input().split()))
    
    if K in A:
        print(A.index(K))
    else:
        print(-1)
    
  • 例2

  • _, K = map(int, input().split())
    A = list(map(int, input().split()))
    print(A.index(K) if K in A else -1)
    

    .index()メソッドは、特定の値が含まれている場合にその要素番号を返します。

    「含まれていない場合は -1 を出力」とあるので.find()メソッドを使いたいところですが、リスト型には.find()メソッドは存在しません。
    仕方がないので自分で -1 を画面に出力して対処します。

STEP: 7 要素の種類数

要素の種類数

  • 例1

  • N = int(input())
    A = [int(input()) for _ in range(N)]
    print(len(set(A)))
    
  • 例2

  • N = int(input())
    A = {int(input()) for _ in range(N)}
    print(len(A))
    

    リストをセットに変換すると、要素の重複分が削除されます。この時の残った要素数がそのまま結果となります。

    例2は初めからセットで受け取っています。

    セット(集合)については「2章 セットさんは重複を許さない」で学習できます。

FINAL問題 【配列を参照する操作】全ての要素に対する操作

【配列を参照する操作】全ての要素に対する操作

    N, K = map(int, input().split())
    A = [int(input()) for _ in range(N)]
    for num in A:
        print(num + K)
    

    リストの先頭から順に要素を拾い、その値に K を足したものを画面に出力していきます。

【配列への副作用を伴う操作】条件を満たす要素のみの配列作成

【配列への副作用を伴う操作】条件を満たす要素のみの配列作成

STEP: 1 配列の順序の反転

配列の順序の反転

  • 例1

  • N = int(input())
    A = [int(input()) for _ in range(N)]
    for num in A[::-1]:
        print(num)
    
  • 例2

  • N = int(input())
    A = [int(input()) for _ in range(N)]
    for num in reversed(A):
        print(num)
    

    もう1つ、.reverse()メソッドもありますが、文を使って要素を1つ1つ表示していくだけですので、リストの中身を書き換えてしまう.reverse()メソッドは使わないほうがよろしいかと思います。

STEP: 2 変数の入れ替え

変数の入れ替え

    X, Y = map(int, input().split())
    X, Y = Y, X
    print(X, Y)
    

    「2 つの変数の中身を入れ替えた後の」とありますので、print(Y, X) とはせずに、値を入れ替えてから print(X, Y) と出力します。

STEP: 3 指定要素の入れ替え

指定要素の入れ替え

    N = int(input())
    A = [int(input()) for _ in range(N)]
    X, Y = map(int, input().split())
    
    A[X-1], A[Y-1] = A[Y-1], A[X-1]
    print(*A, sep='\n')
    

    どうでしょう?スワップにはもう慣れましたか?😸

STEP: 4 末尾への要素の追加

末尾への要素の追加

    N = int(input())
    A = [int(input()) for _ in range(N)]
    B = int(input())
    
    A.append(B)
    print(*A, sep='\n')
    

    リストの末尾への要素の追加は.append()メソッドを使います。

STEP: 5 指定位置への要素の追加

指定位置への要素の追加

    N = int(input())
    A = [int(input()) for _ in range(N)]
    n, B = map(int, input().split())
    
    A.insert(n, B)
    print(*A, sep='\n')
    

    要素の挿入.insert()メソッドを使います。要素番号 n に B を要素として挿入します。

    問題文には「B を A_n の後ろに追加」とありますが、n は 1 番目から数え、要素番号は 0 番目から数えますので、n に 1 を足さずにそのまま n と書いて大丈夫です。

    n 番目 1 2 3 4
    要素番号 0 1 2 3

    2 番目の後ろは、要素番号 1 の後ろの 要素番号 2 のこと。

STEP: 6 指定要素の削除

指定要素の削除

  • 例1

  • N = int(input())
    A = [int(input()) for _ in range(N)]
    n = int(input())
    
    del A[n-1]
    print(*A, sep='\n')
    
  • 例2

  • N = int(input())
    A = [int(input()) for _ in range(N)]
    n = int(input())
    
    A.pop(n-1)
    print(*A, sep='\n')
    

    削除する要素番号を間違えないように気を付けてくださいね。

    n 番目 1 2 3 4
    要素番号 0 1 2 3

    2 番目は、要素番号 1 のこと。

STEP: 7 九九表

九九表

  • 例1

  • kuku = []
    for i in range(1, 10):
        kuku.append([])
        for j in range(1, 10):
            kuku[i-1].append(i * j)
    
    for result in kuku:
        print(*result)
    
  • 例2

  • kuku = []
    for i in range(1, 10):
        kuku.append([i*j for j in range(1, 10)])
    
    for result in kuku:
        print(*result)
    
  • 例3

  • kuku = [[i*j for j in range(1, 10)] for i in range(1, 10)]
    
    for result in kuku:
        print(*result)
    
  • 例4

  • for i in range(1, 10):
        print(*range(i, i*9+1, i))
    

    例1は、掛け算の結果を1つずつリストに格納していってます。
    例2は、九九の段数ごとにリストを作ってから kuku に追加していってます。
    例3は、内包表記を使って一息に書いたものです。
    例4は、掛け算ではなく、range()関数の step の機能だけで並べたものです。

    どれが正しいということはありませんし、他にもまだ書き方があります。

STEP: 8 全ての要素を用いた処理

全ての要素を用いた処理

    N = int(input())
    A = [int(input()) for _ in range(N)]
    for i in range(1, N):
        for j in range(i):
            print(A[i] * A[j])
    

    二重ループを用いて器用にも重複しない組み合わせを作っています。この二重ループがどのように動いているのかを見える化してみます。プログラム例と見比べてみてください。

    N = 5 の時

    i j
    1 0
    2 0 1
    3 0 1 2
    4 0 1 2 3

    i と j の列を左右反対にしてみるとわかりやすく、見事に組み合わさっているのがわかると思います。i を 0 から始めても j が1回もループしないので、i は 1 からスタートしています。

    あとはこの i と j を添字にして、この組み合わせで掛け算して画面に出力していきます。組み合わせ問題は難しいですね。😓

STEP: 9 配列のサイズの変更

配列のサイズの変更

    N, n = map(int, input().split())
    A = [int(input()) for _ in range(N)]
    
    result = [0] * n
    for i in range(N):
        if i < n:
            result[i] = A[i]
    
    print(*result, sep='\n')
    

    難しく書かれていますけど、要するにやることはゼロマップ( 0 で埋め尽された配列)をつくってから所定の要素の値を書き換えるだけです。今回は リストA の先頭から n 番目までの要素を、ゼロマップの先頭から n 番目までに書き写すだけです。
    ゼロマップの要素数より書き写した要素数のほうが少ないと、手を付けられていない 0 がそのまま残ります。それが問題文の最後にある「サイズが合うように 0 を A の要素の末尾に追加してください。」の結果となります。

    N = 3, n = 5, A = [1, 2, 3] の時

    n 番目 1 2 3 4 5
    リスト A 0 0 0 0 0

    ↓ 3 番目までを 1, 2, 3 で書き換えると・・・

    n 番目 1 2 3 4 5
    リスト A 1 2 3 0 0

    ゼロマップを作ることはよくあります。[0] * n という書き方は憶えておきましょう。

STEP: 10 重複要素の削除

重複要素の削除

    N = int(input())
    A = list(map(int, input().split()))
    
    B = []
    for num in A:
        if num not in B:
            B.append(num)
    
    print(*B, sep='\n')
    

    要するに、「要素の順番を変えずに重複した要素を削除していく」ということです。セットに変換すると順番がめちゃくちゃになりますので、リストのまま地道に作業していきます。

    新たに配列 B を作成するということなので、「値が リストB にすでにある場合」はなにもせず、初めて登場する値だけを リストB に追加していきます。

FINAL問題 【配列への副作用を伴う操作】条件を満たす要素のみの配列作成

【配列への副作用を伴う操作】条件を満たす要素のみの配列作成

    N, K = map(int, input().split())
    A = [int(input()) for _ in range(N)]
    
    B = []
    for num in A:
        if num >= K:
            B.append(num)
    
    print(*B, sep='\n')
    

    リストB を作成する条件が変わっただけで、1つ前の問題「重複要素の削除」とほぼ同じプログラムになります。

【配列に対しての複雑な処理】集団行動

【配列に対しての複雑な処理】集団行動

STEP: 1 傾斜配点

傾斜配点

    N = int(input())
    M = list(map(int, input().split()))  # 各科目の重み
    
    points = [0] * N  # 各受験者の5科目の合計点
    for i in range(N):
        A = list(map(int, input().split()))
    
        for j in range(5):
            points[i] += A[j] * M[j]  # 重みを掛ける
    
    print(max(points))
    

    まず人数分のゼロマップ(points)を作成しておきます。ここに各受験者の最終得点が記録されます。

    次にループで各受験者の各科目の得点に重みを掛けていきます。全ての受験者の計算を終えると、points には各受験者の最終得点が格納されています。

    このリストから最大値を取って画面に出力すれば完了です。

STEP: 2 内定

内定

    N, K, M = map(int, input().split())
    A = [int(input()) >= K for _ in range(N)]
    
    result = max(sum(A) - M, 0)
    
    print(result)
    

    極力簡潔な書き方をしましたが、このプログラム例で解説します。

    二行目の標準入力の所で、入力と同時にいきなり K 点以上の人かどうかを、比較式を使って判定しています。

    N = 5, K = 3974, M = 0
    A_i
    2049
    4690
    6867
    3414
    460 の時

    A = [False, True, True, False, False]
    

    となります。

    次にsum(A)についてですが、数値でないのに総和を求めようとしています。これは「2章 bool型 True と False」で詳しく説明していますが、True1False0 でもあります。この特性があるゆえにsum()関数で総和を求めることが出来るのです。
    上の リストA の場合は、

    A = [0, 1, 1, 0, 0]
    

    と同等になります。

    max(sum(A) - M, 0) は、sum(A) - M0 の大きいほうが最大値として選ばれます。もし sum(A) - M でマイナスの値(負数)になった場合は 0 のほうが大きいので、0 が最大値として選ばれます。つまり最低でも「 0 人」となるわけです。
    このmax()関数の使用目的は、最大値や、より大きいほうを求めているというよりは「最低値を設定している」と言うほうが適切と言えます。憶えておくといつか役に立ちます。😸

    このリスト内包表記の書き方は「2章 内包表記」で学習できます。
STEP: 3 queue (9) 係

queue (9) 係

    N = int(input())
    
    A = []
    for _ in range(N):
        S = input().split()
    
        if S[0] == 'in':
            A.append(S[1])
        elif S[0] == 'out' and A:
            A.pop(0)
    
    print(*A, sep='\n')
    

    初期の リストA は空の状態で初期化します。

    次に N 個の指示を受け取るのですが、'in' と 'out' で受け取る要素数が異なります。ここは一旦 input().split() で受け取ります。

    受け取った指示 S の要素番号 0 には 'in' か 'out' が入っていますので、これを使って文をつくります。

    'in' の時は、S の要素番号 1 に整数 n が入っています。これを リストA の末尾に追加します。
    'out' の時は、リストA の先頭の要素を削除するのですが、リストA が空の場合は何もしないことになっています。何もない要素を削除しようとするとエラーになりますので、リストの中身が空かどうかを調べる必要があります。

    A = []
    A.pop(0)
    
    Traceback (most recent call last):
      File "Main.py", line 2, in 
        A.pop(0)
    IndexError: pop from empty list
    

    elif ~ and A という所で、リストが空かどうかをチェックしています。
    これについては「2章 bool型 True と False」で学習できます。

    S[0]'out' の時、且つ、リストA に要素がある時」に、リストA の先頭の要素を削除します。

    それ以外の時は、なにもしません。else: 以降を省略しています。なにもしないから何も書くことないし~。

    また、こういう書き方もできます。

    if S[0] == 'in':
        A.append(S[1])
    else:
        del A[:1]
    

    スライスは指定の範囲に要素が存在していなくてもエラーにはなりません。しかし else は「その他全ての条件」を受け入れてしまいますので、意図しない動作を生んでしまう恐れがあります。

    if S[0] == 'in':
        A.append(S[1])
    elif S[0] == 'out':
        del A[:1]
    

    これなら少しは安心です。😽

    最後に リストA を画面に出力して完了となります。

    queue は「キュー」と読みます。キュー (Wikipedia)
    データの出し入れを、リストの後ろから入れて(.append())、前から取り出す(.pop(0))という方式で行ないます。
    もう1つ、スタック (Wikipedia) というものがあり、こちらはデータの出し入れを、リストの後ろから入れて(.append())、後ろから取り出す(.pop())という方式で行ないます。

    理屈は単純なのですが、プログラミングにおいて重要な要素であり、paiza の問題集 (定番アルゴリズム「スタック・キューメニュー」) にも用意されています。『アルゴリズム』なんて書いてありますけど、数あるアルゴリズムの中でもかなり簡単なほうです。この「配列活用メニュー」が終わったら挑戦できるくらいのものですので、興味がありましたらどうぞ。😜

STEP: 4 二人三脚

二人三脚

    N = int(input())
    A = [int(input()) for _ in range(N)]
    
    pairs = [0, 0]  # 身長差が最も小さい2人の身長
    min_ = float('inf')  # 最も小さい身長差
    for i in range(1, N):
        for j in range(i):
            if (tmp := abs(A[i] - A[j])) < min_:
                pairs[0] = A[i]
                pairs[1] = A[j]
                min_ = tmp
    
    print(*sorted(pairs), sep='\n')
    

    これはこの前の「【配列への副作用を伴う操作】条件を満たす要素のみの配列作成」「STEP: 8 全ての要素を用いた処理」と同じ方法の組み合わせ問題ですね。

    真ん中あたりにある := については「3章 補足」で学習できます。

    文は、もし現在の身長差の最小値を下回る組み合わせが登場したら、pairsmin_ を新しい値に更新します。

    最後までループし終えたら身長を昇順ソートし、画面に出力して完了です。

    abs(A[i] - A[j])は、身長が高いほうから低いほうを引いても、またその逆でも、身長差は同じです。173 - 170 でも 170 - 173 でも3差です。どちらから引いてもいいように絶対値をとって正数に補正しています。

STEP: 5 場所取り

場所取り

  • 例1

  • N, K, F = map(int, input().split())
    A = [int(input()) for _ in range(K)]
    
    del A[:F]
    
    order = []
    for num in A:
        if num not in order:
            order.append(num)
    
    print(*order, sep='\n')
    
  • 例2

  • N, K, F = map(int, input().split())
    A = [int(input()) for _ in range(K)]
    
    del A[:F]
    
    order = set()
    for num in A:
        if num not in order:
            print(num)
            order.add(num)
    

    まず先頭から F 個の要素を削除します。スライスを使って削除する場合は del を使います。.pop()は1つの要素しか扱えません。

    残りの部分は、要素の順番を変えずに重複を取り除く作業です。order の中に num があればなにもしない、なければ ordernum を追加します。最後に order を画面に出力して完了です。

    例2は、登場した値を order に記憶し、すでに登場した値があればなにもしない、初めて登場した値ならば、その場で値を画面に出力していきます。

    このメニューの流れで考えれば例1ですが、どちらかというと例2の方法が今後使う機会が多いと思われます。

STEP: 6 ボウリング

ボウリング

    pins = [int(i) for _ in range(4) for i in input().split()][::-1]
    print(pins.index(1) + 1)
    print(pins.count(1))
    

    一行目の入力のしかたをすると、4行の入力を一次元リストで並べることができます。
    この時、ピンの配列が 10 → 1 になっているので、これを反転して 1 → 10 にします。

    ピンの番号
    [10, 9, 8, 7, 6, 5, 4, 3, 2, 1][::-1]

    [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

    先頭の1番ピンから最初の 1 を見つけ、その要素番号に 1 を足して画面に出力します。.index()は探し物が見つからなかったときにはエラーとなりますが、条件に「少なくとも 1 本のピンが残っていることが保証されています。」とありますので、エラーは起こりません。

    最後に .count(1)1 の数を数えたものを画面に出力して完了です。

    入力を

    pins = [list(map(int, input().split())) for _ in range(4)]
    

    とすると、二次元リストになります。

    pins = [[1, 1, 1, 1], [1, 1, 1], [1, 1], [1]]

    これを

    pins = sum(pins, [])
    

    とすると、なぜか

    pins = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

    と、一次元リストになります。オジサンビックリダ
    二次元リストを一次元リストに変換する方法の1つで、数ある方法の中でも処理速度は最遅と言われてますが、一番簡単に書ける方法ですので憶えておくといつか役に立つでしょう。

FINAL問題 【配列に対しての複雑な処理】集団行動

【配列に対しての複雑な処理】集団行動

    N, Q = map(int, input().split())
    
    nums = list(range(1, N+1))
    
    for _ in range(Q):
        S = input().split()
        
        if S[0] == 'reverse':
            nums = nums[::-1]
        elif S[0] == 'resize' and len(nums) > (C:=int(S[1])):
            del nums[C:]
        elif S[0] == 'swap':
            A, B = int(S[1]), int(S[2])
            nums[A-1], nums[B-1] = nums[B-1], nums[A-1]
    
    print(*nums, sep='\n')
    

    「STEP: 3 queue (9) 係」と同じ、指示を受け取って処理をするクエリ(query)問題です。各処理内容を落ち着いて考えていけば難しいことはありません。

    列の入力は与えられていませんので、自分で作る必要があります。nums = list(range(1, N+1))

    文の中で入力を1つずつ受け取り、都度文でクエリを処理します。
    最初の の後半は、問題文の「列が既に C 人以下の場合」にあたります。問題文では「何も行わない」とありますが、逆に何かする場合は「列が C 人より多い」条件で式を書きます。それが len(nums) > (C:=int(S[1])) です。

    クエリの問題ではクエリの入力の長さが不規則なことがほとんどです。これをどのように受け取り、読みやすく、理解しやすく書いていくかが難しいところだと思います。プログラム例では問題と照らし合わせやすいように A B C の変数(定数)を使いたかったのでちょっとねじ込む形になりましたけど😅。この先学びを進めていく中で、気分転換にぜひ過去の問題を振り返って書き直したりしてみてください。

    (C:=int(S[1])):= については「3章 補足」で学習できます。