如何使用Python逻辑检查回文字符串

57

我想使用Python检查回文。 我目前的代码使用循环次数很多的 for 循环。

在我看来,从C语言转到Python时人们犯的最大错误是试图使用C逻辑来实现Python代码,这会使得代码运行缓慢,并且无法充分利用Python语言的特点。

这个网站上,搜索"C-style for",可以看到Python没有C风格的for循环。 虽然可能已经过时,但我理解为Python有自己的方法。

我尝试了一些查询,但并没有找到最新(Python 3)的关于如何不使用for循环解决回文问题的建议。

在课堂上我已经用C语言完成了这个问题,但我想个人挑战一下用Python解决它。 这个问题来自欧拉计划,顺便说一下,这是一个很棒的网站。

def isPalindrome(n):
    lst = [int(n) for n in str(n)]
    l=len(lst)
    if l==0 || l==1:
        return True
    elif len(lst)%2==0:
        for k in range (l)
        #####
    else:
        while (k<=((l-1)/2)):
            if (list[]):
                #####   

for i in range (999, 100, -1):
    for j in range (999,100, -1):
        if isPalindrome(i*j):
            print(i*j)
            break

这里缺少很多代码。这五个#号只是提醒自己的。

具体问题:

  1. 在C语言中,我会制作一个for循环,将索引0与索引最大值进行比较,然后将索引0 + 1与max-1进行比较,直到某些条件满足。在Python中如何更好地做到这一点?

  2. 我的for循环(在in range(999、100、-1)中),在Python中是否有更好的方法?

  3. 是否有任何好的建议、有用的网站或资源适用于我这种情况的人? 我不是程序员,也没有成为程序员的愿望,我只想学习足够的知识,以便在撰写本科论文(电气工程)时,不必同时学习适用的编程语言并尝试获得良好的项目结果。 “从基本的C到优秀的Python应用程序”,这样的东西。

  4. 任何使此问题具有极佳解决方案的特定代码也将不胜感激,我需要学习良好的算法... 我正在设想3种情况:如果该值为零或一位数,如果长度为奇数,如果长度为偶数。我打算写for循环...

附:问题是:找到两个三位数的最大乘积,其也是回文数。


1
相关链接:http://stackoverflow.com/a/7460573/846892 - Ashwini Chaudhary
2
我相信这是ProjectEuler #4。你应该能够找到一些解决方案,可以介绍给你Python。但从外观上看,你的实现并不糟糕。你的isPalindrome可以更简单。你可能还想将所有找到的回文存储在一个列表中,然后对其进行排序以找到最高值。如果你只是break,你不能保证得到最高值的回文。 - wflynny
1
所有这些答案都不错,但请记住,正如所述,您的单词/短语必须是一个完全回文才能起作用,包括大小写、空格和标点符号。如果您想匹配像“Do geese see God?”这样的情况,您需要查看像.lower().translate()这样的方法来使情况统一并除去空格和标点符号。 - Crowman
@PaulGriffiths 谢谢你,我在这个特定的程序中处理数字,但我已经看到了 .lower() 和 .upper() 函数,.translate() 我会研究一下。非常感谢! - DrOnline
仅为澄清对这个问题的未来访问者。C语言检查回文的方式将涉及到像下面这样的for循环:for(int i=0; i<len(str)/2; i++) if str[i] != str[len(str)-i-1]: return False - Ghos3t
36个回答

207

判断给定值是否为回文的Pythonic方式:

str(n) == str(n)[::-1]

解释:

  • 我们正在检查 n 的字符串表示是否等于 n 的反向字符串表示
  • [::-1] 切片负责反转字符串
  • 之后,我们使用 == 进行相等比较

8
它并没有做其他事情,只是检查单词是否等于它的反转。Python 的优势在于它允许你在更高的抽象层次上工作,从而实现更清晰、更优雅的解决方案。 - mariosangiorgio
1
@DrOnline 我更新了我的答案。这是使用Python的方式来编写解决方案,通过操作语言提供的非常灵活的列表数据结构。 - Óscar López
3
@DrOnline,“::” 部分被称为“切片”,可以在这里阅读有关它的全部内容。 - Óscar López
17
[::-1]是高级切片操作。[a:b:c]表示从a(包含)到b(不含)每隔c个元素进行切片。 - wflynny
这个切片看起来很像numpy的切片版本。然而,我发现numpy比普通的Python性能更好。这个操作执行起来速度是否与numpy数组版本的相同操作类似? - chase
显示剩余3条评论

32

与那种相当晦涩难懂的[::-1]语法不同,这里有个替代方案:

>>> test = "abcba"
>>> test == ''.join(reversed(test))
True

reversed 函数返回 test 中字符的反向序列。

''.join() 将这些字符再次无间隔地连接在一起。


3
我认为 ''.join(reversed(test))[::-1] 一样不直观。真正直观的行为应该是能够编写 test == reversed(test)。 (我不是那个给你点反对票的人。) - Benjamin Hodgson
6
您可以使用list(test) == list(reversed(test))来实现。 - Rob

15

仅供记录,对于那些寻找更算法化的验证给定字符串是否回文的人,有两种方法可以实现相同的结果(使用whilefor循环):

def is_palindrome(word):

    letters = list(word)    
    is_palindrome = True
    i = 0

    while len(letters) > 0 and is_palindrome:       
        if letters[0] != letters[(len(letters) - 1)]:
            is_palindrome = False
        else:
            letters.pop(0)
            if len(letters) > 0:
                letters.pop((len(letters) - 1))

    return is_palindrome

还有...第二个:

def is_palindrome(word):

    letters = list(word)
    is_palindrome = True

    for letter in letters:
        if letter == letters[-1]:
            letters.pop(-1)
        else:
            is_palindrome = False
            break

    return is_palindrome

9
Python的可爱之处在于你可以用它做许多事情。对于字符串,你不必使用索引。以下方法可以实现同样的效果(使用切片)。
def palindrome(n):
    return n == n[::-1]

它所做的就是将n反转并检查它们是否相等。n[::-1] 将 n 反转(-1 的意思是递减)

"2) 我的 for 循环 (in range (999, 100, -1)),在 Python 中这样做是不好的吗?"

关于上面的问题,您应该使用 xrange 而不是 range(因为 range 会创建一个实际的列表,而 xrange 则是一个快速的生成器)

我的问题3的看法

在学习 Python 之前,我学了 C,然后阅读了文档,并使用控制台进行了试验(还通过解决 Project Euler 问题来练习 :)


1
请注意,xrange 仅在 Python 2 中需要(并且仅存在于 Python 2 中)。在 Python 3 中,常规的 range 行为类似于以前的 xrange(增加了一些额外的新功能,例如切片以获取不同的 range 对象)。 - Blckknght
1
没问题!如果你想要一些索引,使用 xrange。如果你想要一个列表并对其进行其他操作,请使用 range - jh314
谢谢Blckknght,我在使用xrange时遇到了错误,不知道是否需要包含库或其他东西。好知道了!有点像raw_input和input合并成了input,我知道那是Python 3的改变。 - DrOnline

8
以下代码将打印0,如果它是回文字符串的话,否则它将打印-1优化后的代码
word = "nepalapen"
is_palindrome = word.find(word[::-1])
print is_palindrome

输出: 0

word = "nepalapend"
is_palindrome = word.find(word[::-1])
print is_palindrome

输出: -1

解释:

在搜索字符串时,返回的值是字符串开始位置的值。

因此,当您执行word.find(word[::-1])时,它在位置0找到nepalapen并且[::-1]反转了nepalapen,并且它仍然是nepalapen在位置0,所以返回0

现在,当我们搜索nepalapend,然后将nepalapend反转为dnepalapen时,它会生成一个FALSE语句,因为nepalapend被反转为dnepalapen,导致搜索无法找到nepalapend,从而导致返回值为-1,表示字符串未找到。


另一种方法是如果是回文则打印true,否则打印false

word = "nepalapen"
print(word[::-1]==word[::1])

输出结果:


4

还有一种 函数式 方法:

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

2
这段代码存在一个小错误:“mannam”会导致IndexError: string index out of range,因为最内层的调用是在空字符串上进行的(如果给它一个空字符串也是如此)。 if len(word) <= 1: return True解决了这个问题,尽管它会将空字符串视为回文。 - TemporalWolf

2

我知道这个问题已经有一段时间没有回答了,对于打扰表示抱歉。不过,我也在尝试用Python实现这个功能,并且想分享我的实现方式如下:

word = 'aibohphobia'

word_rev = reversed(word)

def is_palindrome(word):
    if list(word) == list(word_rev):
        print'True, it is a palindrome'
    else:
        print'False, this is''t a plindrome'

is_palindrome(word)

1
我刚刚发现了一种更简单的方法,只需要1行代码。
is_palindrome = word.find(word[::-1])

你可以把它变成一个布尔值,例如:is_palindrome = word.find(word[::-1]) == 0。仍然+1。 - t.m.adam

1
最符合Python风格的做法是使用切片符号来反转字符串,就像之前提到的那样:
def is_palindrome(string: str) -> bool:
    return string == string[::-1]

在一些其他场合(比如技术面试)中,你可能需要编写一个“正式”的算法来查找回文。在这种情况下,以下代码应该能够解决问题:

def is_palindrome(string: str) -> bool:
    start = 0
    end = len(string) - 1
    
    while end >= start:
        if string[end] != string[start]:
            return False
        start += 1
        end -= 1
        
    return True
  • 将指针设置为字符串的开头和结尾
  • end超过start时进行迭代
  • 如果endstart索引中的字符不匹配,则这不是回文,否则继续比较
  • 增加start指针1个单位
  • 减少end指针1个单位

测试用例:

import unittest

class Test(unittest.TestCase):

    palindromes = ['a', 'aa', 'aba', '12321']
    non_palindromes = ['ab', 'aab', 'cacacc']
    def test_is_palindrome(self):
        for case in self.palindromes:
            self.assertTrue(is_palindrome(case))

        for case in self.non_palindromes:
            self.assertFalse(is_palindrome(case))


if __name__ == '__main__':
    unittest.main()

1
您可以使用这个一行代码返回一个布尔值: str(x)==str(x)[::-1] 由于类型转换的原因,它适用于单词和数字。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接