はじめに
どうもkudokaiです!
最近、大学を卒業して新卒として都内でiOSエンジニアとして働いています。
最近とあるコミュニティに参加し、そのコミュニティで知り合ったフリーランスエンジニアの方と雑談をしている中でカプレカ数というものを知りました。
きっとそのフリーランスエンジニアの方は数学がお好きなんでしょう。
僕は数学は苦手(一応、理系大学出身なのに...)ですが、カプレカ数の概要を知った時はカプレカ数の虜になりました。
カプレカ数とは
任意の正の整数nを各桁ごとに並び替え、「並び替えてできた最大の数」-「並び替えてできた最小の数」= 元の正の整数nになる数をカプレカ数といいます。
上記で述べた
「並び替えてできた最大の数」-「並び替えてできた最小の数」
の計算のことをカプレカ操作といいます。
3桁の任意の正の整数にカプレカ操作を適用すると495のみ、4桁の任意の正の整数にカプレカ操作を適用すると6174のみであるという特徴があります。
カプレカ操作を適用した場合の例外として以下があります。
- 任意の正の整数がゾロ目の場合は0になる
- 「並び替えてできた最大の数」-「並び替えてできた最小の数」で得られた値が2桁の場合は10倍して、再度カプレカ操作を適用する
すごくないですか!?
この時点で僕はめっちゃカプレカ数の魅力に惹かれました。
ここで、3桁の任意の正の整数にカプレカ操作を適用した例を書きます。
任意の正の整数n = 708とします。(これは適当)
870 - 78 = 792
972 - 279 = 693
963 - 369 = 594
954 - 459 = 495
495になったぞ!!!
では適当にもう1パターン。
任意の正の整数n = 323とします。(これは適当)
332 - 233 = 99
990 - 99 = 891
981 - 189 = 792
972 - 279 = 693
963 - 369 = 594
954 - 459 = 495
また495になったぞ!!!
上記で述べたように3桁の任意の正の整数にカプレカ操作を適用すると495になるわけですね。
実におもしろい。
4桁についても同様な手順を適用すると最終的に6174になります。
気になった方はヨビノリさんが動画の中でカプレカ数の証明しているので、以下のリンクからご覧ください。
https://youtu.be/GtKVrd-ap84
Swiftを使って実装
そもそもこういう数学系の課題をSwiftで実装しようなんて人は少数だと思いますが、僕はSwift好きなのでSwiftで実装しますね。
ちなみに効率については考慮せずに書きました...
任意の整数を昇順・降順に並べる
- 任意の整数をIntで受け取って、文字列型配列→整数型配列に変換(いきなり整数型配列に変換すると各桁ごとに抜き出せないので...)
- その後、昇順・降順に並び替える
let stringNumbers = String(number).compactMap { String($0) }
let numbers = stringNumbers.compactMap{Int($0)}
let ascNumbers = numbers.sorted()
let descNumbers = numbers.sorted(by: >)
var ascNumber = 0
var descNumber = 0
for index in 0 ..< ascNumbers.count {
ascNumber += ascNumbers[index] * Int(pow(Double(10), Double(ascNumbers.count - index - 1)))
}
for index in 0 ..< descNumbers.count {
descNumber += descNumbers[index] * Int(pow(Double(10), Double(descNumbers.count - index - 1)))
}
ascNumberが昇順結果、descNumberが降順結果になります。
カプレカ操作を複数回適用
今回はループを100回に設定してカプレカ操作を行いました。(正直、こんなに試行回数必要ないんですけどね...)
var kaprekarNumber: Int
var result = sortNumber(number: number)
for _ in 0 ..< 100 {
kaprekarNumber = result.desc - result.asc
if kaprekarNumber < 100 { kaprekarNumber *= 10 }
if kaprekarNumber < 1000 && number >= 1000 { kaprekarNumber *= 10 }
if kaprekarNumber == 0 { return }
}
sortNumber(number: Int)は任意の整数を昇順・降順に並べるメソッドになります。
コード全体
import Foundation
func sortNumber(number: Int) -> (asc: Int, desc: Int) {
let stringNumbers = String(number).compactMap { String($0) }
let numbers = stringNumbers.compactMap{Int($0)}
let ascNumbers = numbers.sorted()
let descNumbers = numbers.sorted(by: >)
var ascNumber = 0
var descNumber = 0
for index in 0 ..< ascNumbers.count {
ascNumber += ascNumbers[index] * Int(pow(Double(10), Double(ascNumbers.count - index - 1)))
}
for index in 0 ..< descNumbers.count {
descNumber += descNumbers[index] * Int(pow(Double(10), Double(descNumbers.count - index - 1)))
}
return (ascNumber, descNumber)
}
func calculateKaprekarNumber(number: Int) {
print("初期値:\(number)")
var kaprekarNumber: Int
var result = sortNumber(number: number)
for _ in 0 ..< 100 {
kaprekarNumber = result.desc - result.asc
print("\(result.desc) - \(result.asc) = \(kaprekarNumber)")
if kaprekarNumber < 100 { kaprekarNumber *= 10 }
if kaprekarNumber < 1000 && number >= 1000 { kaprekarNumber *= 10 }
if kaprekarNumber == 0 { return }
result = sortNumber(number: kaprekarNumber)
}
}
calculateKaprekarNumber(number: Int.random(in: 100 ..< 10000))
実行結果を複数パターン載せておきます。
初期値:4368
8643 - 3468 = 5175
7551 - 1557 = 5994
9954 - 4599 = 5355
5553 - 3555 = 1998
9981 - 1899 = 8082
8820 - 288 = 8532
8532 - 2358 = 6174
7641 - 1467 = 6174
7641 - 1467 = 6174
7641 - 1467 = 6174
7641 - 1467 = 6174
.
.
.
.
.
初期値:6654
6654 - 4566 = 2088
8820 - 288 = 8532
8532 - 2358 = 6174
7641 - 1467 = 6174
7641 - 1467 = 6174
7641 - 1467 = 6174
.
.
.
.
.
初期値:690
960 - 69 = 891
981 - 189 = 792
972 - 279 = 693
963 - 369 = 594
954 - 459 = 495
954 - 459 = 495
954 - 459 = 495
.
.
.
.
.
この他にも5桁の場合はカプレカ数なし、6桁の場合のカプレカ数は549945, 631764の2つになります。
それ以上の桁数についても特定の桁数の場合にカプレカ数は存在します。
きっともっと効率のいい書き方があると思うのですが、カプレカ数について衝動的に気になったので実装してみました。
何かお気づきの点がありましたら、お気軽にコメントしていただければ嬉しいです。