Help us understand the problem. What is going on with this article?

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で公開したものをに加筆・修正したものです。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした