Javaアルゴリズム問題を解いてみた(基礎問題)

だいぶ古い記事ですが、CodeZineの過去の連載で
「脱 超初心者 Javaアルゴリズム問題集」というものをみつけました。
https://codezine.jp/article/corner/58
記事によると、「プログラム経験が3ヶ月もあれば十分解くことができるでしょう。」
という難易度らしいので、今の自分にはちょうどよいと思いました。
４問しか記事が見つけられませんでしたが、基礎を復習する意味で時間も意識して実施しています。

以下、問題文を引用させていただいてます。
`正答例は記事で御覧ください。`
脱 超初心者 Javaアルゴリズム問題集
https://codezine.jp/article/corner/58

#第1回　条件分岐と永久ループ
標準入力された値があればそのまま表示、値がなければエラーメッセージを表示するプログラムを作成してください。なお、「EXIT」が入力されるまで、処理を繰り返し続けるものとします。

###所要時間目安　　A：30分　B：60分　C：120分(A：（開発歴）2年以上、B：1年程度、C：3ヶ月程度を目安)

コマンドラインに入力を待ち受けるための「>」を表示する。
「EXIT」が入力された時点でプログラムを終了する。それ以外が入力された場合は「未入力です」と表示して、再び入力待ち受け状態にする。
###キーワード
if文の使用法を習得する。
while()／for(;;)による永久ループの使用法を習得する。
###ポイント
標準入力からの入力を受け取るストリームはSystemクラスのフィールドinよりInputStreamクラスのインスタンスとして取得できる。
永久ループは次のようにすることによって表すことができる。

```java
    public static void main(String[] args) {
        question1();
    }

    public static void question1() throws IOException {
        System.out.print(">");
        InputStreamReader writeConsole = new InputStreamReader(System.in);
        BufferedReader buffer = new BufferedReader(writeConsole);
        String writeString = buffer.readLine();
        while (true) {
            if (writeString.equals("")) {
                System.out.println("未入力です");
            } else {
                System.out.println(writeString);
            }
            System.out.print(">");
            writeString = buffer.readLine();
            if (writeString.equals("EXIT")) {
                System.exit(0);
            }
        }
    }
```
永久ループの手法、InputStreamReaderを使った入力を知られて勉強になった。

#第2回　条件分岐（複合条件）
標準入力された月、日が、今日であるかどうかを判定するプログラムを作成してください。

###所要時間目安　　A：30分　B：60分　C：120分(A：（開発歴）2年以上、B：1年程度、C：3ヶ月程度を目安)

コマンドラインに「今日は何月何日でしょう？」のメッセージを表示する。
それぞれ、「何月？==> 」「何日？ ==> 」を表示して入力を受け取る。
入力された月日が今日であれば「正解！！」、間違っていれば「間違っています」と表示する。
###キーワード
if文における複合条件の使用方法を習得する。
###ポイント
日付の取得は、Calendarクラスを用いて行う。通常のクラスのようにコンストラクタをnewせずgetInstance()メソッドを呼び出してインスタンスを取得する。
標準入力は、Int型で受け取る。
if文は1度しか使用しない。

```java
    public static void main(String[] args) {
        question2();
    }

    public static void question2() throws IOException {
        System.out.println("今日は何月何日でしょう？");
        int rightNowMonth = Calendar.getInstance().get(Calendar.MONTH) + 1;
        int rightNowDate = Calendar.getInstance().get(Calendar.DATE);
        BufferedReader buffer1 = new BufferedReader(new InputStreamReader(System.in));

        System.out.print("何月？==>");
        int writeMonth = Integer.parseInt(buffer1.readLine());
        System.out.print("何日？==>");
        BufferedReader buffer2 = new BufferedReader(new InputStreamReader(System.in));
        int writeDate = Integer.parseInt(buffer2.readLine());
        if (rightNowMonth == writeMonth && rightNowDate == writeDate) {
            System.out.println("正解！！");
        } else {
            System.out.println("間違っています");
        }
    }
```
日付の扱いについての理解が深まった。

#第3回　ループ
標準入力から、n個の年齢を受け取り、その平均年齢を算出するプログラムを作成してください。年齢はコマンドライン引数から取得するものとします。

###所要時間目安　　A：20分　B：40分　C：90分(A：（開発歴）2年以上、B：1年程度、C：3ヶ月程度を目安)
年齢は、コマンドライン引数から取得する。
コマンドライン引数が指定されていない場合は「引数に年齢を指定してください」のメッセージを表示する。
###キーワード
for文を使い、n個のループ処理を理解する。
入力チェックを理解する。
###ポイント
コマンドライン引数はmain()メソッドにStringの配列型として引き渡される。

```java
    public static void main(String[] args) {
        if (args.length == 0) {
            System.out.println("引数に年齢を指定してください");
        } else {
            int sumAge = 0;
            for (String age : args) {
                sumAge += Integer.parseInt(age);
            }
            int averageAge = sumAge / args.length;
            System.out.println("平均年齢は " + averageAge + " 歳です");
        }
    }
```
コマンドライン引数を扱うことが少なかったので、良い経験になった。

#第4回　多重ループと二次元配列
掛け算九九表を出力するプログラムを作成してください。

###所要時間目安　　A：30分　B：50分　C：100分（開発歴）2年以上、B：1年程度、C：3ヶ月程度を目安)
二次元配列を作成して、九九データの代入を行い、その後の表示は分けて作成する。
ヘッダー、フッタ及び、列ヘッダー（段の表示）は、省いても構いません。
###キーワード
for文を使った多重ループ処理を理解する。
二次元配列への代入、参照を理解する。
###ポイント
数字を桁をそろえて出力するにはDecimalFormatクラスを使用する。0詰め2桁で出力するにはnewするときにコンストラクタに"00"を渡す。

```java
public static void main(String[] args) {
        System.out.println("+--------- かけ算九九表 --------+");
        System.out.println("|     1  2  3  4  5  6  7  8  9 |");
        System.out.println("|  +----------------------------|");
        int h = 1;
        for (int[] list : question4()) {
            // List<Integer>を利用する場合は以下
            // for (List<Integer> list : question4_2()) {
            System.out.print("| " + h++ + "|");
            for (int value : list) {
                if (value < 10) {
                    System.out.print(" 0" + value);
                } else {
                    System.out.print(" " + value);
                }
            }
            System.out.print(" |\n");
        }
        System.out.println("+--+----------------------------+");
    }
    //配列を使用
    public static int[][] question4() {
        int[][] list = new int[9][9];
        for (int outer = 0; outer < 9; outer++) {
            int[] value = new int[9];
            for (int inner = 0; inner < 9; inner++) {
                value[inner] = (outer + 1) * (inner + 1);
            }
            list[outer] = value;
        }
        return list;
    }
    //Listを使用
    public static List<List<Integer>> question4_2() {
        List<List<Integer>> list = new ArrayList<List<Integer>>();
        for (int outer = 1; outer <= 9; outer++) {
            List<Integer> value = new ArrayList<Integer>();
            for (int inner = 1; inner <= 9; inner++) {
                value.add(outer * inner);
            }
            list.add(value);
        }
        return list;
    }

```
出力結果の見た目までこだわって実装したので楽しかった。

すべての問題を1問あたり1時間以内に解答でき、楽しめました。
4問目の2次元配列の問題は、Listと配列両方の実装方法を解答しています。
それぞれの違いは、要素数が固定か否かくらいしか理解してませんでしたが、改めて調べると、データへのアクセス方法が異なるため、処理速度に違いがあるらしいことがわかりました。

||要素へのアクセス|要素の追加|
|:-:|:-:|:-:|
|配列|高速|低速|
|List|低速|高速|