プログラミング再入門

ボケ防止にプログラミングの勉強を始めた。毎日のようにコードを書いていたころから10年以上が経過していて、言語(というかライブラリ)も変わっているし、記憶も錆び付いていてつらい気もする一方で、仕事ではない気楽さもあって、プラマイではとてもよい気晴らしになっている。ここ一週間はcoderbyte.comの無料問題を端っこから解いている。多言語対応が適当で、Javaメソッド名が大文字で始まっていたり、booleanではなくStringの"true"を返すように期待されていたり、気持ちの悪いところはあるが、他の人の回答例を見て色々考えたりできるもの楽しい。

今日のお題

最低2種類の数字を含む4桁の整数を入力として、各桁の数字を降順にソートした整数と昇順にソートした整数の差を求める操作をして、その差についてさらに同様の操作を繰り返すと6174になる。6174になるまでの操作の回数を返すメソッドを書け。

回答

問題の定義からし再帰の初歩的な問題であるが、Javaに用意されたクラスライブラリを適切に使って文字列や整数を操作しようとするとギコチナイことになる。

import java.util.*;
import java.io.*;

class Main {
    public static int KaprekarsConstant(int num) {
        return recursiveDiff(num, 1);
    }

    public static int recursiveDiff(int num, int depth) {
        int diff = sortDesc(num) - sortAsc(num);
        if (diff == 6174) {
            return depth;
        } else {
            return recursiveDiff(diff, depth + 1);
        }
    }

    public static int sortAsc(int num) {
        String numStr = "" + num;
        char[] numChars = numStr.toCharArray();
        Arrays.sort(numChars);
        return Integer.parseInt(new String(numChars));
    }

    public static int sortDesc(int num) {
        int sortedInt = sortAsc(num);
        String sortedStr = "" + sortedInt;
        String reverseSortedStr;
        if (sortedInt >= 1000) {
            reverseSortedStr = "" + sortedStr.charAt(3) + sortedStr.charAt(2) + sortedStr.charAt(1)
                    + sortedStr.charAt(0);
        } else {
            reverseSortedStr = "" + sortedStr.charAt(2) + sortedStr.charAt(1) + sortedStr.charAt(0) + '0';
        }
        return Integer.parseInt(reverseSortedStr);
    }

    //mainやmainから呼ばれるメソッドのシグネチャはcoderbyteのお作法
    public static void main(String[] args) {
        // keep this function call here
        Scanner s = new Scanner(System.in);
        System.out.print(KaprekarsConstant(Integer.parseInt(s.nextLine())));
    }
}

感想

テストケースはパスしたものの、自分のコードは1000など0が2つ以上含まれている整数を食わせるとクラッシュする。ソート済みの数字のペアのうち、小さい方を返すsortAscを使ってsortDescを実装するのがうまくない。同じことをするにしても、sortDescは必ず1000以上の整数になることが保証されているので、sortDescを使ってsortAscを実装すれば場合分けは不要になる。

そもそもなぜsortAscが頭の中で先に来たかというと、Arrays.sortにコンパレータを指定して逆順ソートする方法Arrays.sort(num, Collections.reverseOrder())が頭に入っていなかったから。