kakashi-blog・カカシブログ・

Python備忘録を書きドローンやバイクなど好きな事で生きて行こうとしているブログ

Python

カプレカ数をPythonで求める|20桁まで一気に計算

投稿日:2021年10月10日 更新日:

6174や495のような「カプレカ数」を、Pythonで求めてみました。

結論から言うと、1つずつ数字を調べる方法では、5分回しても6個目が出てきませんでした。ところが、数字の並べ方(組み合わせ)で調べる方法に変えると、20桁までのカプレカ数が約1分で全部求まりました。

要点

  • カプレカ数は、数字を並べ替えた「最大」から「最小」を引くと、元の数に戻る数です
  • 1つずつ調べる方法では、6桁の631764までで止まってしまいました
  • 数字の組み合わせだけを調べると、調べる数がぐっと減って一気に速くなります
  • 20桁までに、カプレカ数は0を含めて66個ありました

カプレカ数とは

6174を例にします。

  1. 6174を、6、1、7、4のように1けたずつバラバラにします
  2. それを、一番大きくなる順(7641)と、一番小さくなる順(1467)に並べ替えます
  3. 最大から最小を引きます。7641 − 1467 = 6174

このように、最大 − 最小 = 元の数 になる数がカプレカ数です。4桁では、6174のほかにはありません。考え方はとてもシンプルです。

なお、「カプレカ数」という名前は、2乗した数を2つに分けて足すと元に戻る数(45など)を指すこともあります。この記事のカプレカ数は、並べ替えて引く方のカプレカ数です。

1つずつ計算して調べてみる

1つずつ手で計算するのは面倒すぎるので、Pythonで書いてみました。学習の題材としても、いい課題になると思います。

import copy

num = 0
while num <= 99999999999999999999:  # 20桁まで求めてみる
    n = []
    for i in range(len(str(num))):
        n.append(str(num)[i])

    n.sort()              # 並べ替え(小さい順)
    s = copy.copy(n)
    n.sort(reverse=True)  # 並べ替え(大きい順)
    s = ''.join(s)        # リストの数字を1つの数字の列にする
    n = ''.join(n)
    kap = int(n) - int(s)  # 最大 − 最小

    if kap == num:        # カプレカ数か判断
        print(num)
    num += 1

結果:5分回しても6個目が出なかった

0
495
6174
549945
631764

数秒で5個は出てきましたが、その後は時間がかかりすぎて、途中でやめました。5分回しても6個目が出てきません。20桁なんて夢でした。

この方法では、0から順番に、すべての数を1つずつ調べています。20桁までだと1垓(いちがい)回も計算することになるので、終わるはずがありませんでした。

速い方法:数字の組み合わせで調べる

よく考えると、「最大 − 最小」の答えは、使っている数字の組み合わせだけで決まります。たとえば6174も7641も1467も、使っている数字は同じ「1、4、6、7」なので、引き算の答えは全部同じ6174です。

そこで、数を1つずつ調べるのではなく、数字の組み合わせを1回ずつだけ調べる ことにしました。そして、引き算の答えが、同じ数字の組み合わせでできているかを確かめます。

from itertools import combinations_with_replacement
import time

start = time.time()
for keta in range(1, 21):  # 1桁から20桁まで
    for digits in combinations_with_replacement('0123456789', keta):
        small = ''.join(digits)  # 小さい順に並べた数
        big = small[::-1]        # 大きい順に並べた数
        kap = int(big) - int(small)
        # 答えが同じ数字の組み合わせで、同じ桁数ならカプレカ数
        if sorted(str(kap)) == list(digits) and len(str(kap)) == keta:
            print(kap)
print('かかった時間', round(time.time() - start, 1), '秒')

combinations_with_replacement は、同じ数字を何回使ってもいい組み合わせを作る関数です。20桁でも組み合わせは約1,000万通りなので、1垓回に比べるとほんのわずかです。

結果:20桁まで約1分で全部出た

このコードを動かすと、20桁までのカプレカ数が0を含めて66個出てきました。15桁までなら約5秒、20桁までで約53秒でした(時間はパソコンの性能で変わります)。

桁数 カプレカ数
1桁 0
3桁 495
4桁 6174
6桁 549945、631764
8桁 63317664、97508421
9桁 554999445、864197532
10桁 6333176664、9753086421、9975084201
11桁 86431976532
12桁 555499994445、633331766664、975330866421、997530864201、999750842001

13桁より大きいものも、20桁まで続けて出てきます。2、5、7桁には、カプレカ数はありませんでした。

1つずつ調べた方法で6個目が出なかったのは、7桁にカプレカ数がなく、次が8桁の63317664だったからです。1つずつの方法だと、6300万回以上計算しないとたどり着きません。

まとめ

  • カプレカ数は、数字を並べ替えた「最大 − 最小」が元の数に戻る数です
  • 1つずつ調べる方法では、6桁の631764までしか出せませんでした
  • 数字の組み合わせで調べると、20桁までの66個が約1分で求まりました
  • 計算の回数を減らす工夫をすると、プログラムは何万倍も速くなります

専門家ではないので、誤りなどを見つけた方は教えていただけると助かります。

ほかにも、Pythonの練習問題としてFizzBuzz問題を書いた記事があります。


退屈なことはPythonにやらせよう 第2版 ―ノンプログラマーにもできる自動化処理プログラミング

-Python
-, ,

執筆者:


comment

メールアドレスが公開されることはありません。 ※ が付いている欄は必須項目です

関連記事

PythonのPillowで画像処理|切り抜き・回転・リサイズの基本

画像処理というと大げさですが、PythonのPillow(ピロー)を使って、画像を少し操作してみました。 結論から言うと、Image.open() で読み込めば、crop() で切り抜き、rotate …

Seleniumで自動ログインする方法|Python備忘録

前回はSeleniumでブラウザをスクロールさせました。今回は、ログイン画面にIDとパスワードを自動で入力して、ログインするところまでやってみます。 結論から言うと、開発者ツール(F12)で入力欄とボ …

Python Tkinter入門|ウインドウ・ラベル・入力欄・ボタンの基本

PythonのTkinter(ティーケーインター)を使うと、ボタンや入力欄のある画面(GUI)を作れます。この記事では、ウインドウを開いて、ラベル、テキストの入力欄、ボタンを付けるまでの基本をまとめま …

Amazonのスクレイピングは禁止?Seleniumで試した結果と正しい方法

PythonでAmazonの商品名・価格・ASINコードを集めようとして、普通のスクレイピングでは取れず、何時間も悩んだことがあります。 結論から言うと、Amazonは利用規約でロボットなどによる自動 …

Tkinterのメッセージボックスで出る謎ウインドウの消し方

Pythonのtkinterでメッセージボックスだけを出したいのに、何もない小さなウインドウ(謎ウインドウ)が一緒に出てきて、処理が止まってしまうことがあります。 結論から言うと、謎ウインドウの正体は …