R / Richie全部文章 ↑

Python · 2 分钟阅读

09:回文数

目录


题目

给你一个整数 x,如果 x 是回文整数,返回 True;否则返回 False。
回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

示例

输入:x = 121
输出:True     解释:正读 121,反读 121

输入:x = -121
输出:False    解释:正读 -121,反读 121-

输入:x = 10
输出:False    解释:正读 10,反读 01

约束

  • -2³¹ <= x <= 2³¹ - 1

思路概览

方法 思路 时间 空间
方法一 字符串 + 反转比较 O(log n) O(log n)
方法二 反转一半数字 O(log n) O(1)
方法三(拓展) 直接将整数转为字符串再反转 O(log n) O(log n)

观察:负数一定不是回文数;以 0 结尾的非零数(10, 100, ...)也不可能是。


方法一:字符串法(最直观)

class Solution:
    def isPalindrome(self, x: int) -> bool:
        s = str(x)
        return s == s[::-1]
  • 思路:转字符串,反转后比较。
  • 优点:实现最简单。
  • 缺点:需要额外 O(log n) 的字符串空间。

方法二:反转一半数字(推荐 O(1) 空间)

class Solution:
    def isPalindrome(self, x: int) -> bool:
        # 1) 负数不行;2) 以 0 结尾的非零数不行
        if x < 0 or (x % 10 == 0 and x != 0):
            return False

        reverted = 0
        # 当原数还大于反转部分时,继续反转
        while x > reverted:
            reverted = reverted * 10 + x % 10
            x //= 10

        # 偶数位:x == reverted
        # 奇数位:reverted 多了一位中间数字,整除 10 后比较
        return x == reverted or x == reverted // 10

关键点解释

  • x % 10 取最低位,x //= 10 去掉最低位;
  • 循环终止条件 x <= reverted 意味着“已经反转了超过一半”;
  • 奇数位数(如 12321)时,reverted = 123,x = 12,中间那个数字
    落在 reverted 的最低位,所以比较 x == reverted // 10。

复杂度

  • 时间:O(log₁₀ n) —— 处理约一半位数。
  • 空间:O(1) —— 几个变量。

测试用例

def test():
    s = Solution()
    assert s.isPalindrome(121) is True
    assert s.isPalindrome(-121) is False
    assert s.isPalindrome(10) is False
    assert s.isPalindrome(0) is True
    assert s.isPalindrome(12321) is True
    assert s.isPalindrome(123321) is True
    assert s.isPalindrome(1001) is True
    assert s.isPalindrome(1000021) is False
    print("all passed")


test()

常见追问

  • 能不能完全不用字符串? 用方法二即可,O(1) 空间。
  • 想用 reversed(str(x)) 写法? 可以,但每轮都新建迭代器,性能不如切片。
    return str(x) == "".join(reversed(str(x)))
    
  • 能处理负数 -121 算回文吗? 题目要求“不算”;如果业务上需要,需要先把符号
    单独处理。