LeetCode 第9题:回文数(Python3解法)

1:问题描述

来源:LeetCode

难度:简单


问题详情:
给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false

回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

  • 例如,121 是回文,而 123 不是

输入:x = 121
输出:true

输入:x = -121
输出:false
解释:从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。

输入:x = 10
输出:false
解释:从右向左读, 为 01 。因此它不是一个回文数

进阶:你能不将整数转为字符串来解决这个问题吗?


2:问题分析

从给出的示例可以看出:

扫描二维码关注公众号,回复: 15330840 查看本文章
  • 负数不是回文数
  • 位数大于1且末尾为0的数不是回文数

同时,也可以想到:

  • 只有1位的数是回文的

2.1 时间复杂度和空间复杂度

在真正开始介绍各种算法前,先以表格形式展示各自的时间复杂度和空间复杂度。

算法 时间复杂度 空间复杂度
字符串法 O ( l o g ( x ) ) O(log(x)) O(log(x)) O ( l o g ( x ) ) O(log(x)) O(log(x))
直接法 O( l o g ( x ) log(x) log(x)) O ( 1 ) O(1) O(1)
折半法 O( l o g ( x ) log(x) log(x)) O ( 1 ) O(1) O(1)

2.2 字符串法

2.2.1 代码

根据进阶要求的限制,我们反而能够很容易想到这个解法。将数字转换为字符串列表,然后反转列表,再转换为数字对比是否与反转前相等即可。
同时将分析得到的三种情况先做一个返回。

def isPalindrome(x: int) -> bool:
    """不满足进阶要求"""
    if x < 0:
        return False
    if 0 <= x <= 9:
        return True
    if x % 10 == 0:
        return False
    rev_x = int(''.join(list(str(x))[::-1]))
    if rev_x == x:
        return True
    else:
        return False

由于数字长度可以用 i n t ( l o g 10 ( x ) ) + 1 int(log10(x))+1 int(log10(x))+1计算得到,因此时间复杂度为 O ( l o g ( x ) ) O(log(x)) O(log(x))
对于空间复杂度,由于其需要一个列表存储每一位数值,因此空间复杂度为 O ( l o g ( x ) ) O(log(x)) O(log(x))

2.3 直接法

2.3.1 代码

不使用字符串的前提下,我们就需要真的将数值反转过来对比。

def isPalindrome2(x: int) -> bool:
    """数值计算转换"""
    if x < 0:
        return False
    if 0 <= x <= 9:
        return True
    if x % 10 == 0:
        return False
    rev_x = 0
    s = x
    while s:
        s, t = divmod(s, 10)
        rev_x = rev_x * 10 + t
    if rev_x == x:
        return True
    else:
        return False

由于数字长度可以用 i n t ( l o g 10 ( x ) ) + 1 int(log10(x))+1 int(log10(x))+1计算得到,因此时间复杂度为 O ( l o g ( x ) ) O(log(x)) O(log(x))
对于空间复杂度,其为 O ( 1 ) O(1) O(1)

2.3 折半法

2.3.1 代码

折半法其实是直接法的优化,因为其实我们并不需要将所有的位数都反转,而只需反转一半,然后对比是否与另一半未反转的相同即可。

举例来说,1221,我们只需反转后半部分的2112,然后对比前半部分看是否一致。

def isPalindrome4(x: int) -> bool:
    if x < 0:
        return False
    if 0 <= x <= 9:
        return True
    if x % 10 == 0:
        return False

    rev_x = 0
    while x > rev_x:
        x, t = divmod(x, 10)
        rev_x = rev_x * 10 + t

    return rev_x == x or rev_x // 10 == x

虽然思想上比较简单,但是,我们如何判断当前已经完成了一半的反转了呢?

对此,我们可以反过来想,当还未完成反转的时候有什么特点?

  • 那就是前半部分的位数比后半部分的位数多,可以使用前半部分>反转的后半部分作为循环判断的依据。
  • 但是在位数相同的情况下,也可以达到前半部分>后半部分这种情况。比如3221这个数,其在反转的过程中够实现这个特例,32>12
    对此,我们只能让后半部分暂时占点便宜,让其再次循环多取走一位,变成3 < 122这样就可以终止循环。
    然后我们就前部分==后部分 或者 前部分==后部分//10 作为返回值。可以判断前半部分3和后半部分122这两个判断条件都不满足,就是false了。

前部分==后部分//10 这个条件是为了应对输入的数x位数是奇数的情况,比如121。
按照while的流程:

前半部分 后半部分
121 0
12 1
1 12

我们可以看出,前部分占了1位,后半部分占了2位,我们需要使用前部分==后部分//10 去除多后半部分出来的末位2,去除后左右两边都为1,返回true.

由于数字长度可以用 i n t ( l o g 10 ( x ) ) + 1 int(log10(x))+1 int(log10(x))+1计算得到,因此时间复杂度为 O ( l o g ( x ) ) O(log(x)) O(log(x))
对于空间复杂度,其为 O ( 1 ) O(1) O(1)

猜你喜欢

转载自blog.csdn.net/weixin_43490422/article/details/126681762