回文计划可以做出哪些改进?

时间:2012-06-07 12:45:16

标签: python palindrome

我只是在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()

我可以做些什么其他改进来提高效率吗?

6 个答案:

答案 0 :(得分:9)

我认为用即兴创作在Python中编写回文检查功能的最佳方法如下:

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

(根据需要添加lower()电话。)

答案 1 :(得分:3)

什么方式更简单?你为什么要创建一个类而不是一个简单的方法?

>>> is_palindrome = lambda x: x.lower() == x.lower()[::-1]
>>> is_palindrome("ciao")
False
>>> is_palindrome("otto")
True

答案 2 :(得分:3)

虽然其他答案已经讨论了如何最好地处理Python中的回文问题,但让我们来看看你在做什么。

您正在使用索引循环遍历字符串。虽然这有效,但它不是非常Pythonic。 Python for循环旨在循环遍历您想要的对象,而不仅仅是数字,就像在其他语言中一样。这允许您剪切出一层间接,使您的代码更清晰,更简单。

那么我们怎么能在你的情况下做到这一点?那么,你想要做的是在一个方向上循环字符,在另一个方向上循环 - 同时。我们可以使用zip()reversed()内置函数很好地完成此操作。 reversed()允许我们以相反的方向获取字符,而zip()允许我们一次迭代两个迭代器。

>>> 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中以不同方式处理事物的一个很好的例子。

答案 3 :(得分:2)

建立在Lattyware的答案上 - 通过适当地使用Python内置函数,你可以避免像a_string[-(i+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:]))

这适用于所有偶数长s,但奇数长度s失败,因为RHS将是一个更长的元素。但是,你不关心它中的最后一个字符,因为它是字符串的中间字符 - 它不会影响它的回文性。如果你zip两个在一起,它会在短的一个结束后停止 - 你可以像原始循环一样比较一个角色:

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

您甚至不需要''.joinlist等。但是你仍然可以做得更好 - 这种循环是如此惯用,以至于Python有一个名为all的内置函数,只为你做这件事:

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

表示'列表前半部分中的所有字符与向后写入的列表后半部分中的字符相同'。

答案 4 :(得分:1)

我可以看到的一个改进是使用xrange而不是range。

答案 5 :(得分:0)

它可能不是更快的实现,但您可以使用递归测试。既然你正在学习,这种结构在很多情况下非常有用:

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

由于这是一个相当简单(轻量级)的函数,这种结构可能不是最快的,因为多次调用函数的开销,但在计算更密集的其他情况下,它可能是一个非常有效的结构。 / p>

只是我的两分钱。