演習: 配列
各問題のコードは、Main クラスの main メソッドの中に書く前提です。
配列の宣言には2つの書き方があります:
- リテラル:
int[] arr = {1, 2, 3}; new演算子:int[] arr = new int[3];(要素は 0 で初期化される)
この章では主にリテラル記法を使います。配列の長さは arr.length で取得できます。
5-A. 配列の宣言と表示
Section titled “5-A. 配列の宣言と表示”配列の長さ: に続けて配列の長さを、次の行に各要素を半角スペース区切りで出力してください。
int[] numbers = {3, 1, 4, 1, 5, 9, 2, 6};出力例:
配列の長さ: 83 1 4 1 5 9 2 6ヒント
numbers.length で配列の長さが取得できます。for ループでインデックス 0 から numbers.length - 1 まで走査して、各要素を表示します。
System.out.println は改行付き、System.out.print は改行なしで出力します。要素を1行にまとめたいので print を使い、要素間の区切り(半角スペース)は自分で付ける必要があります。最後にループの外で System.out.println() を呼ぶと、最終行の末尾に改行を入れられます。
5-B. 合計と平均
Section titled “5-B. 合計と平均”整数配列の合計と平均を計算して出力してください。平均は小数で表示します。
int[] scores = {72, 85, 64, 90, 78};出力例:
合計: 389平均: 77.8ヒント
合計は int で計算します。平均を求めるときは、整数同士の / は整数除算となり結果が 77 になるため、片方を double にキャストする必要があります(例: (double) 合計 / 要素数)。
5-C. 最大値
Section titled “5-C. 最大値”気温の配列から最高気温を出力してください。最高気温: に続けて値を出力します。
int[] temperatures = {15, 22, 18, 30, 25, 17, 28};出力例:
最高気温: 30ヒント
最初の要素を仮の最大値とし、インデックス 1 以降の要素と順に比較していきます。比較対象がより大きければ、最大値の変数を更新します。
5-D. 拡張 for で表示
Section titled “5-D. 拡張 for で表示”文字列配列の各要素を、拡張 for 文(for-each 文)を使って1行ずつ出力してください。
String[] fruits = {"apple", "banana", "cherry", "date"};出力例:
applebananacherrydateヒント
拡張 for 文の構文:
for (要素の型 変数 : 配列) { // 変数 を使って各要素にアクセス}インデックスを意識せずに、配列の要素を先頭から順に取り出せます。インデックスが必要ない処理では、通常の for より簡潔に書けます。
5-E. フィボナッチ数列の生成
Section titled “5-E. フィボナッチ数列の生成”フィボナッチ数列の最初の n 項を配列に格納し、半角スペース区切りで出力してください。n は 1 以上の整数とします。
フィボナッチ数列の定義:
F(0) = 0F(1) = 1F(i) = F(i-1) + F(i-2)(i ≥ 2)
int n = 10;出力例(n=10 のとき):
0 1 1 2 3 5 8 13 21 34n を 1、5、15 などに変えて確認してください。
ヒント
長さ n の配列を new int[n] で作成します。インデックス 0 に F(0)=0、インデックス 1 に F(1)=1 を設定し、2 以降を for ループで前 2 項から計算して埋めていきます。
n が 1 のときは配列の長さも 1 で、arr[1] への代入は配列範囲外になります。arr[1] に値を入れる前に、配列の長さが 2 以上であることを確認してください。
5-F. 線形探索(break で早期終了)
Section titled “5-F. 線形探索(break で早期終了)”整数配列の中から target と一致する最初の要素のインデックスを出力してください。見つからない場合は -1 を出力します。break を使って、見つかった時点でループを抜けてください。
int[] numbers = {7, 2, 9, 4, 6, 1, 8, 3, 5};int target = 6;出力例(target=6 のとき):
6 が見つかった位置: 4target を 10 などに変えて、-1 が出力されることも確認してください。
ヒント
見つかったインデックスを保持する変数を -1 で初期化しておき、配列を走査する中で一致を見つけたら値を更新して break でループを抜けます。ループが終わった時点での変数の値を出力します。
5-G. 指定値の全出現位置(continue でスキップ)
Section titled “5-G. 指定値の全出現位置(continue でスキップ)”整数配列の中で target と一致するすべての要素のインデックスを、半角スペース区切りで1行に出力してください。continue を使って、target 以外の要素はスキップします。
int[] numbers = {3, 7, 2, 7, 5, 7, 1, 8, 7};int target = 7;出力例(target=7 のとき):
1 3 5 8target が配列に存在しない場合は、改行のみで何も出力しません。
ヒント
for ループで配列を走査し、要素が target と一致しなければ continue で次のループへ進みます。一致した場合のみ、そのインデックスを出力します。
if の中で出力する書き方でも同じ結果になりますが、ここでは continue の使い方を確認します。
5-H. 安全な配列アクセス
Section titled “5-H. 安全な配列アクセス”整数配列と、アクセスしたいインデックスの配列が与えられます。各インデックスについて、範囲内なら要素の値を、範囲外なら「範囲外」を出力してください。
int[] numbers = {10, 20, 30};int[] indices = {0, 2, 5, -1, 1};出力例:
インデックス 0: 10インデックス 2: 30インデックス 5: 範囲外インデックス -1: 範囲外インデックス 1: 20直接 numbers[5] のように範囲外アクセスをすると、実行時エラー(ArrayIndexOutOfBoundsException)でプログラムが停止します。これを避けるため、アクセス前にインデックスが範囲内かをチェックします。
ヒント
インデックス i が配列 arr の範囲内であることをチェックするには、i が 0 以上かつ arr.length 未満であることを確認します。&& で結合した複合条件を if で判定します。
indices の各要素については、拡張 for 文または通常の for 文で走査します。
5-I. ヒストグラム描画
Section titled “5-I. ヒストグラム描画”整数配列を、各要素の値の数だけアスタリスク(*)を表示するヒストグラムとして描画してください。各行は 値: に続けて、値の数だけアスタリスクを並べた形式で出力します。
int[] data = {3, 5, 0, 2, 8, 4};出力例:
3: ***5: *****0:2: **8: ********4: ****要素は正の整数または 0 を想定します。0 の場合はアスタリスクなしで値とコロンだけ表示してください。
ヒント
外側の for ループで配列を走査し、内側の for ループで各要素の値の回数だけアスタリスクを出力します。
各行の構成:
- 値とコロンを表示
- アスタリスクを値の回数だけ表示
- 改行
5-J. 店舗別売上の集計(2次元配列)
Section titled “5-J. 店舗別売上の集計(2次元配列)”3 店舗 × 4 ヶ月分の売上データから、各店舗の合計と全体の総合計を計算して出力してください。
int[][] sales = { {120, 95, 130, 110}, // 渋谷店 {145, 100, 125, 140}, // 新宿店 {130, 110, 140, 125} // 池袋店};String[] shops = {"渋谷店", "新宿店", "池袋店"};出力例:
渋谷店: 455新宿店: 510池袋店: 505総合計: 1470ヒント
2次元配列はネストした for 文で走査します。外側のループで店舗(行)、内側のループで月(列)を回します。sales[i][j] で shops[i] の j 月目の売上にアクセスします。
sales.length が店舗の数(行数)、sales[i].length が各店舗の月数(列数)です。
5-K. 配列の左ローテーション
Section titled “5-K. 配列の左ローテーション”整数配列を左に k 個分ローテーションしてください。元の配列を直接書き換えます。
int[] numbers = {1, 2, 3, 4, 5, 6, 7};int k = 3;左に 3 回ローテーション: {1, 2, 3, 4, 5, 6, 7} → {4, 5, 6, 7, 1, 2, 3}
出力例:
4 5 6 7 1 2 3k が配列長より大きい場合(例: k = 10、配列長 7)は、k % length で正規化して扱ってください。
ヒント
配列をその場で書き換えると、まだ参照していない値が上書きされる可能性があります。元の配列をコピーした original を用意し、original から読んで numbers に書き込みます。
結果の numbers[i] に入れる値は、original のうちインデックスが k だけ大きい位置の要素です(例: 結果の numbers[0] には original[k] が入る)。インデックスが length を超えたら先頭に戻すため、% length を組み合わせます。
5-L. Fisher-Yates シャッフル
Section titled “5-L. Fisher-Yates シャッフル”整数配列を Fisher-Yates アルゴリズムでシャッフルし、シャッフル後の配列を出力してください。元の配列を直接書き換えます。
int[] numbers = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};Fisher-Yates アルゴリズム:
- インデックス
iを末尾から先頭に向かって走査(i = length - 1からi >= 1まで) - 各
iについて、0 ≤ j ≤ iの範囲でランダムなインデックスjを選ぶ numbers[i]とnumbers[j]を交換
実行ごとに結果が変わります。出力例の1つ:
3 7 1 9 4 10 2 8 5 6Fisher-Yates: すべての並び順が等しい確率で出現することが数学的に保証されている、定番のシャッフルアルゴリズム。
ヒント
ランダムな整数 j(0 ≤ j ≤ i)を作るには、(int)(Math.random() * (i + 1)) で求められます。
numbers[i] と numbers[j] の交換には、一時変数を1つ使います。
5-M. エラトステネスの篩
Section titled “5-M. エラトステネスの篩”n 以下の素数をすべて見つけて、半角スペース区切りで出力してください。エラトステネスの篩を使います。
int n = 30;エラトステネスの篩:
- 2 以上
n以下の整数をすべて「素数候補」として並べる i = 2から順に見ていき、iがまだ素数候補なら、iの倍数(2i、3i、…)を候補から除外するiを√nまで進めた時点で、候補として残った数がすべての素数
出力例(n=30 のとき):
2 3 5 7 11 13 17 19 23 29n を 10、50、100 などに変えて確認してください。
エラトステネスの篩: 古代ギリシアのエラトステネスが考案した、素数を効率的に求める古典アルゴリズム。
ヒント
各インデックスが素数候補かどうかは、長さ n + 1 の boolean[] で保持できます。初期値は全要素 true、除外する際に false を入れます。
√n を Java で扱うには、(int) Math.sqrt(n) で整数値に丸めるか、ループ条件を i * i <= n と書く方法があります。後者なら Math を使う必要がなく、浮動小数点の誤差も避けられます。
i を √n までで打ち切ってよいのは、n 以下の合成数(素数でない数)は必ず √n 以下の素因数を持つためです。それより大きい i で見つかる倍数は、すでに小さい素因数によって除外されています。