Edited at

C#で数学パズル - LINQを使って2乗した数値が1-9で構成される数を求める

More than 1 year has passed since last update.

小町数を使った数学パズルの第4弾です。


問題

3桁の数値とその数値を2乗した値の各数字が1から9までのすべての数字で構成されるような3桁の数値をすべて求めるプログラムを作成せよ。

例えば 763*763=582169 となるが、これは、1,2,3,5,6,7,8,9 からなり、4が抜けているからダメ。


どうやって解くか

これまで、いくつかの小町数に関連するパズルをプログラム(例えばこことかここ)で解いてきましたが、この問題は、100から999までの数を一つずつ調べていけばいいだけなので、プログラム的には一番優しい小町パズルかな。

下一桁が1, 5, 6ならば解ではないという、知識を使えば、さらに速くできるかもしれませんが、そのための判断に時間がかかるし、コードも複雑になります。

たかだた、999回の試行なので、特に工夫することなく素直なコードにしてみました。


LINQ使わないバージョン

static void Main(string[] args) {

for (var n = 100; n < 1000; n++) {
if (IsKomachi(n))
Console.WriteLine($"{n}の2乗 = {n * n}");
}
}

static private bool IsKomachi(int n) {
char[] array = (n.ToString() + (n * n).ToString()).ToArray();
Array.Sort(array);
var s = new string(array);
return s == "123456789";
}

IsKomachi内の実装はいろいろな方法が考えられますが、ここでは、以下のようなロジックで判断しています。

nとnの2乗を文字列としてつなげ、それを char[]に変換。

文字コード順にソートして、再度文字列に変換。

"123456789"と一致すれば、1-9の数字で構成されると判断。


LINQ使ったバージョンも書いてみました。

class Program {

static void Main(string[] args) {
foreach (var n in Enumerable.Range(100, 900).Where(n => IsKomachi(n)))
Console.WriteLine($"{n}の2乗 = {n*n}");
}

static private bool IsKomachi(int n) {
string s = n.ToString() + (n * n).ToString();
return "123456789".All(c => s.Contains(c));
}
}

LINQのWhereメソッド、Allメソッドを使っています。

ちなみに、IsKomachiメソッド内に以下のコードがあります。

"123456789".All(c => s.Contains(c))

この式ですが、1がsに含まれているか、2がに含まれているか、3がに含まれているか、... 9がに含まれているかを調べ、すべてが成り立てば、trueになります。

return s.Length == 9 && "123456789".All(c => s.Contains(c));

とする必要はありません。999 * 999 = 998001 なので、必ず s.Length <= 9 になりますから、

この式がtrueならば、1-9の数字は一つずつ存在することが保証されます。

無理やり感がありますが、こんなコードでも答えを見つけられます。

static void Main(string[] args) {

Enumerable.Range(100, 900)
.Where(n => {
string s = n.ToString() + (n * n).ToString();
return "123456789".All(c => s.Contains(c));
})
.ToList()
.ForEach(n => Console.WriteLine("{0}の2乗 = {1}", n, n * n));
}


結果

567の2乗 = 321489

854の2乗 = 729316


この記事は、Gushwell's C# Programming Pageで公開したものをに加筆・修正したものです。