回文判断¶
回文(palindrome)是从左到右和从右到左读起来都一样的字符串。比如说,
racecar
和Live on time, emit no evil
都是回文。请注意,我们仅仅考虑字母和数字,且不分大小写。在得到输入字符串后,请判断它是否是回文。
# 范例行为
>>> is_palindrome("Step on no pets!")
True
>>> is_palindrome("'Tis not a palindrome")
False
>>> is_palindrome("Hi, I am Mai Ih")
True
提示¶
str.isalnum返回某字符串是否纯粹由数字和字母字符组成(对单个字符的字符串也可以用)。
>>> "I love Python".isalnum()
False
>>> "IlovePython".isalnum()
True
尝试将其与 str.lower
一起使用来过滤所有非数字字母符号并将所有字符小写化,然后再进行回文判断。
解¶
本题最简单的解如下。我们使用了 str.join
函数以及步距为负的切片:
def is_palindrome(input_str):
""" 判断某字符串是否为回文。忽略空格,
字符大小写,以及非字母数字的字符
Parameters
----------
s: str
输入字符串
Returns
-------
bool
"""
filtered_str = "".join(c.lower() for c in input_str if c.isalnum())
return filtered_str == filtered_str[::-1]
注意 (c.lower() for c in input_str if c.isalnum())
使用了有过滤条件的生成器理解。因此,
"".join(c.lower() for c in input_str if c.isalnum())
等值于以下的代码块:
filtered_str = ""
for char in input_str:
if char.isalnum():
filtered_str += char.lower()
生成器表达式不仅更加简短易读,且其对 str.join
的使用使得创建新列表更加高效。在以上代码块中每次调用 filtered_str += c.lower()
都会在内存中创建一个新字符串,而 str.join
在它消耗可迭代物时仅仅使用单个字符串。
接下来,请回忆,seq[::-1]
使用的步距-1的切片将会返回序列的反向版本。因此,filtered_str == filtered_str[::-1]
允许我们对比 filtered_str
中的第一个字符和原本字符串的倒数第一个字符,如此继续。因此,这等值于:
is_equal = True
for i in range(len(filtered_str)//2): # 请回忆:5//2 -> 2, 6//2 -> 3
if filtered_str[i] != filtered_str[-(i+1)]:
is_equal = False
break
使用切片来进行这个对比的唯一坏处在于它需要复制一份 filtered_str
,而显性的for循环不需要。
在这里指出的效率考量仅仅在 is_palindrome
可能是我们整体代码的效率瓶颈时才值得进行。虽然我们希望读者能够发展编写高效Python代码的直觉,但我们不推荐读者为了过早地优化代码来将代码改得太过难懂。