深入理解回文数 逐层优化

深入理解回文数 逐层优化

题目

给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false

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

提示:-231 <= x <= 231 - 1

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

字符串法

回文数本身就是一个字符串的比较,转化为字符串做易理解。

class Solution:
    def isPalindrome(self, x: int) -> bool:
        return str(x) == str(x)[::-1]

python有黑魔法转字符串太容易了,一行解决属于是不讲武德,使用其他语言稍微麻烦一点。不符合题目进阶要求。

逐位比较

思路

将原数字一位一位取出来,再倒着算回去看是否等于原来的数字。负数一定不是回文数,提前做个判断。

如何将数字一位一位取出来呢?设位数为bit,个位是1,十位是2…可知:(x % (10**bit)) // (10**(bit-1)),先取高一位的余数,去除高位的数字,再用该位整除,去掉低位的数字。

如何将取出来的数字还原呢?将取出的数放在一个数组中,将其在数组中的位置(索引)与位数关联起来(有序放置),乘对应的位数系数即可nums[i] * (10**(length-i-1))

那如何知道最高位是多少呢?当是最高位时,去除高位这一步算出来的数和原来的数是一样的,即取余这一步不会让数字发生改变,条件为:x == x % (10**length)

实现

class Solution:
    def isPalindrome(self, x: int) -> bool:
        if x < 0: return False
        nums, length = [], 0
        while x != x % (10**length):
            length += 1
            temp = (x % (10**length))// (10**(length-1))
            nums.append(temp)
        num = 0
        for i in range(len(nums)):
            num += nums[i] * (10**(length-i-1))
        return num == x 

分析

该方法每位数字要遍历两遍(拆一遍,算一遍),时间复杂度为O(n),系数大致为2。由于使用了临时的nums数组存放每一位的数字,空间复杂度为O(n),比较低效。

回顾思路,导致低效的原因是不知道一共有多少位,在拆的时候必须拆完才知道何时停止,算反转数的时候又要用总位数为参数,导致两次循环。

引入对数计算总位数

思路

因为本题中数字是十进制的,则以10为底计算对数。直接算出的数为浮点数,使用int转换后向下取整了,需要加一length = int(log(x,10)) + 1。需要注意的是,0没有对数,需要单独考虑。

还是一位一位拆,因为知道了总位数,可以边拆边算,少一次循环,而且不需要辅助数组了。在遍历完每一位后,比较两个数是否相等即可。

实现

class Solution:
    def isPalindrome(self, x: int) -> bool:
	    if x < 0: return False
        elif x == 0: return True
        from math import log
        length = int(log(x,10))+1
        num = 0
        for i in range(length):
            temp = (x % (10**(i+1))) // (10**i)
            num += temp * (10**(length-i-1))
        return num == x 

分析

只用遍历一次了,时间复杂度系数小于2了。没有用额外与输入规模相关的内存空间,空间复杂度降为O(1)。

但判断回文数真的需要完整遍历吗?

折半比较

思路

回文数是正反看都一样的数,在上述循环中,因为我们知道了总长度,其实是可以头尾一起看,发现一个不一致就可以返回否了。计算尾端的表达式为:(x % (10**(length-i))) // (10**(length-i-1))

实现

class Solution:
    def isPalindrome(self, x: int) -> bool:
        if x < 0: return False
        elif x == 0: return True
        from math import log
        length = int(log(x,10))+1
        for i in range(length//2 + 1):
            rear = (x % (10**(i+1))) // (10**i)
            pre = (x % (10**(length-i))) // (10**(length-i-1))
            if rear != pre: return False
        return True

分析

只用循环半次,虽然时间复杂度还是O(n),但系数已经降低到1/2左右了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值