LoginSignup
1
1

More than 3 years have passed since last update.

プログラミング初心者(中学生)作ったアルゴリズムを最適化する

Last updated at Posted at 2019-12-01

数学パズル

Python勉強中のK君数学パズル
を持ってきて、これやってみる。と言い出した。

どんな問題かというと10進数、2進数、8進数のいずれでも回文数(12321のような数)で10以上で最小の値を求めるというもの。

皆さんも突っ込みどころ見つけて見てください。


D = list()
E = list()
F = list()
def checker(num):
    a = str(num)
    b = list(reversed(a))
    c = len(b)
    for j in range(c//2):
        if b[j] != b[-j-1]:
            return None
    return num

for i in range(10,1000):
    d = checker(i)
    if d != None:
        D.append(d)

for i in D:
    e = checker(str(oct(i))[2:])
    if e != None:
        E.append(int(e,8))

for i in E:
    f = checker(str(bin(i))[2:])
    if f != None:
        F.append(int(f,2))
print(F)

正解も求まっているのでGood Jobです。

1パスではなくて、まず1000までの10進数の回文数を調べて、見つかった回文数に対して、8進数、2進数でどうかチェックしていく方式。
いろいろ思考錯誤して、付けたししながら作ったんだろうなぁ。

K君のリファクタリングバージョン

でも1パスでできる事に気づいたK君直してきました。

number = 10
result_list = []
def checker(num):
    a = list(reversed(str(num)))
    for j in range(len(a)//2):
        if a[j] != a[-j-1]:
            return None
    return num  

while True:
    if checker(number) != None and checker(str(oct(number))[2:]) != None and checker(str(bin(number))[2:]) != None:
        result_list.append(number)
        print(number)
        break
    else:
        number += 1

これはかなり素直な流れ

料理開始

2進数、8進数の文字列に直す方法はいろいろあり、K君の方法でも問題ないと思いますが、"{:o}".format(number)こんな方法に変えてみました。
ここは、どちらの方法がよいというレベルではないと思います。

一番、不思議なのは、checker関数の戻り値。単純に回文数かどうかを調べるという関数だとしたら、True/Falseを返せばいいと思うんだけどねぇ。

回文かしらべるのに、逆順にした文字を求めようとた名残のreversed(str(num)) 結果的には、これいらないんじゃない?

その当たりをザックリ直してみました。

def checker(num_str):
    for j in range(len(num_str)//2):
        if num_str[j] != num_str[-j-1]:
            return False
    return True

number = 10
while True:
    if (checker(str(number)) and 
        checker( "{:o}".format(number)) and
        checker( "{:b}".format(number))) :
        print(number)
        break
    number += 1

コメントいただいたプログラムがもっとシンプルでわかりやすかったので、追加します

from itertools import count

def is_palindrome(text):
    return text == text[::-1]

for number in count(10):
    if (is_palindrome(f"{number}")
    and is_palindrome(f"{number:o}")
    and is_palindrome(f"{number:b}")):
        print(number)
        break
1
1
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1