前人未踏の領域へ Androidアプリ開発編

Androidアプリ開発に関する調査メモ置き場。古い記事にはアプリ以外も含まれます。

世界のナベアツアルゴリズム

3でアホになるナベアツアルゴリズムを考えてみた。ルールは数式縛り。従ってindexOf()とかは反則。
巷にはもっとよい回答があるのだろうけど、とりあえず思いつくところではこんなもんか。

package way.algorithm;

public class Nabeatsu {

	static final int key = 3;//バカになる数字
	static int counter = 0;//計算回数カウンタ

	public static void main(String[] args) {
		int max = 10000;
		for (int i = 0; i < max; i++) {
			if (checkNabeatsu(i)) {
				System.out.println("---" + i + "---");
			} else {
				System.out.println(i);
			}
		}
		System.out.println("計算回数 " + counter + "回");
	}

	public static boolean checkNabeatsu(int p) {
		counter++;
		if (p / 10 == key || p % 10 == key) {
			return true;//ナベアツ確定
		} else if (p / 10 < 10) {
			return false;
		}
		return checkNabeatsu(p / 10);
	}
}

一晩寝て ver.2

package way.algorithm;
public class Nabeatsu {
	static final int key = 3;
	static int counter = 0;
	public static void main(String[] args) {
		int max = 10000;
		for (int i = 0; i < max; i++) {
			for(int k=i;;k/=10){
				counter++;
				if (k % 10 == key ) {
					System.out.println("---" + i + "---");
					break;
				}else if(k < 10){
					System.out.println(i);
					break;
				}
			}
		}
		System.out.println("計算回数 " + counter + "回");
	}
}

どうやら3のつく数字だけじゃなく3の倍数も含めるらしいのと、30〜39,300〜399,3000〜3999のように連続することが分かっている場合は1桁ごとの計算を省略させたい。
という訳でver.3

package way.algorithm;

public class Nabeatsu {
	public static void main(String[] args) {
		final int key = 3;
		int max = 10000;
		int counter = 0;
		int skipLoop = 0;
		for (int i = 1; i <= max; i++) {
			// 数字ごとに下1桁から順にチェックする。何桁目を評価中かをdに格納
			for (int k = i, d = 1;; k /= 10, d *= 10) {
				counter++;
				// 3で割り切れるか、3を含むか、短縮ループ中かをチェック
				if (i % key == 0 || k % 10 == key || skipLoop > 0) {
					// 3を含む位はSKIPモードに移行
					if (skipLoop == 0 && d > 1) {
						skipLoop = d - i % (d * k);
					}
					System.out.println("---" + i + "---");
					if (skipLoop > 0) {
						skipLoop--;
					}
					break;
				} else if (k < 10) {
					// 全ての桁チェックが終わったら対象外確定
					System.out.println(i);
					break;
				}
			}
		}
		System.out.println("計算回数 " + counter + "回");
	}
}

[実行結果]
1
2
☆3☆
4
5
☆6☆
7
8
☆9☆
10
〜 中略 〜
☆9990☆
9991
9992
☆9993☆
9994
9995
☆9996☆
9997
9998
☆9999☆
10000
計算回数 22682回

とりあえずこれ以上は思いつかないのと、所要時間を考えると自信を失うのに十分な時間をかけたと記しておいて終了。