4

楽しみのためにPythonでプログラミングを学んでいます。私は回文プログラムを書いていて、それをさらに改善する方法を考えました。

最初に頭に浮かんだのは、回文をチェックしているだけなので、プログラムが単語全体を両方の方法で処理する必要がないようにすることです。その後、最初と最後の文字が一致しないとすぐにループが壊れる可能性があることに気付きました。

次に、それらをクラスに実装して、単語を呼び出して true または false を返すことができるようにしました。

現在のプログラムは次のようになっています。

class my_str(str):
        def is_palindrome(self):
                a_string = self.lower()
                length = len(self)
                for i in range(length/2):
                        if a_string[i] != a_string[-(i+1)]:
                                return False
                return True

this = my_str(raw_input("Enter a string: "))
print this.is_palindrome()

より効率的にするために他に改善できる点はありますか?

4

6 に答える 6

9

Python で回文チェック関数を即席で作成する最良の方法は次のとおりだと思います。

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

lower()(必要に応じて呼び出しを追加します。)

于 2012-06-07T12:49:50.480 に答える
3

もっと単純なものはどうですか?単純なメソッドではなくクラスを作成するのはなぜですか?

>>> is_palindrome = lambda x: x.lower() == x.lower()[::-1]
>>> is_palindrome("ciao")
False
>>> is_palindrome("otto")
True
于 2012-06-07T12:49:54.350 に答える
3

Python で回文問題にアプローチする最善の方法について話している他の回答が与えられていますが、あなたが何をしているのか見てみましょう。

インデックスを使用して文字列をループしています。これは機能しますが、あまり Pythonic ではありません。Pythonforループは、他の言語のように単純に数値をループするのではなく、必要なオブジェクトをループするように設計されています。これにより、間接的な層を取り除き、コードをより明確かつ単純にすることができます。

では、あなたの場合、どのようにこれを行うことができますか? さて、あなたがやりたいことは、文字を一方向にループし、同時に反対方向にループすることです。zip()およびビルトインを使用して、これをうまく行うことができますreversed()reversed()文字を逆方向に取得できzip()ますが、一度に 2 つの反復子を反復処理できます。

>>> a_string = "something"
>>> for first, second in zip(a_string, reversed(a_string)):
...     print(first, second)
... 
s g
o n
m i
e h
t t
h e
i m
n o
g s

これは、一度に両方向に文字をループするより良い方法です。もちろん、これはこの問題を解決するための最も効果的な方法ではありませんが、Python で異なる方法でアプローチする方法の良い例です。

于 2012-06-07T12:53:07.213 に答える
2

Lattywareの答えに基づいて構築する-Pythonビルトインを適切に使用することにより、a_string[-(i+1)]理解するのに1秒かかるようなことを避けることができます-そして、回文よりも複雑なものを書くとき、オフバイワンエラーが発生しやすくなります。

秘訣は、それを達成する方法ではなく、何をするつもりかをPythonに伝えることです-したがって、別の答えによると、最も明白な方法は次のいずれかを行うことです:

s == s[::-1]
list(s) == list(reversed(s))
s == ''.join(reversed(s))

または他のさまざまな同様のもの。それらはすべて、「文字列は逆方向の文字列と等しいですか?」と言っています。

何らかの理由で、途中で回文を取得したことを知っている最適化が本当に必要な場合 (通常はそうすべきではありませんが、非常に長い文字列を扱っている可能性があります)、インデックスよりも優れた処理を行うことができます。算術。以下から開始できます。

halfway = len(s) // 2

( //Py3 であっても、または実行した場合でも、結果を整数に強制しますfrom __future__ import division)。これはにつながります:

s[:halfway] == ''.join(reversed(s[halfway:]))

これはすべての偶数長で機能しますが、RHS が 1 要素長くなるため、s奇数長では失敗します。sただし、最後の文字は文字列の中央の文字であるため、回文性には影響しないため、気にする必要はありません。2 つをzip一緒にすると、短いループの終了後に停止します。元のループのように、一度に文字を比較できます。

for f,b in zip(s[:half], reversed(s[half:])):
    if f != b: 
        return False
return True

そして、あなたは必要さえありませ''.joinlist。しかし、もっとうまくやることができます - この種のループは非常に慣用的であるため、Pythonallにはそれを実行するためだけに呼び出される組み込み関数があります。

all(f == b for f,b in zip(s[:half], reversed(s[half:])))

「リストの前半のすべての文字は、逆に書かれたリストの後半の文字と同じです」と言います。

于 2012-06-07T13:23:12.213 に答える
1

私が見ることができる改善の 1 つは、range の代わりに xrange を使用することです。

于 2012-06-07T12:50:32.900 に答える
0

おそらくより高速な実装ではありませんが、再帰テストを使用できます。あなたが学んでいるので、この構造は多くの状況で非常に役立ちます:

def is_palindrome(word): 
    if len(word) < 2:
        return True 
    if word[0] != word[-1]:
        return False 
    return is_palindrome(word[1:-1])

これはかなり単純な(軽い)関数であるため、関数を複数回呼び出すオーバーヘッドがあるため、この構造は最速ではない可能性がありますが、計算がより集中的な他の場合には、非常に効果的な構造になる可能性があります。

ちょうど私の2セント。

于 2012-06-07T15:12:08.590 に答える