LeetCode详解系列的上一题链接:LeetCode详解之如何一步步优化到最佳解法:1.两数之和
9. 回文数
本题题目链接:9. 回文数 - 力扣(LeetCode)
本题的目标
不将整数转为字符串就可以解决这道题。
解法1:暴力解法
代码:
class Solution:
def isPalindrome(self, x: int) -> bool:
corresponding_str = str(x)
length = len(corresponding_str)
for i in range(length//2):
if corresponding_str[i] != corresponding_str[-(i+1)]:
return False
else:
return True
解法性能:
解法分析:
该解法首先将输入的整数转换成一个字符串,然后将这个字符串从两端往中间逐对字符进行比较,若有一对不一样的字符,则返回False;若是到最终都是一样的,则返回True。
对于输入的整数x,我们假设这个整数的位数为N。从复杂度这个角度考虑,因为遍历了一半的字符数,所以时间复杂度为:
O ( N ) O(N) O(N)
然后,定义的变量”corresponding_str”占用的空间为 O ( N ) O(N) O(N),另一个变量”length”占用的空间大小小于”corresponding_str”,所以对于空间复杂度,我们只考虑变量”corresponding_str”。因此,整体的空间复杂度为 O ( N ) O(N) O(N)。
接着,我们考虑优化的方向,首先看一下时间复杂度是否能够优化。因为我们最多需要遍历(N/2)个位(即从两端开始一对字符一直一样,直到最中间的字符),而我们最少需要遍历1位(即第一个字符为”-”,或者只有一位,比如0,1这样的)。因此,我们需要平均至少遍历(N/4)个位。所以,时间复杂度无法继续优化,只能是 O ( N ) O(N) O(N)。
接下来,我们看看是否不需要将输入的整数转换成字符串就能确定是否为回文数,我们可以考虑反转x,并判断反转前后的数是否相等来确定x是否为回文数。具体解法为:
解法2:最终版
代码:
class Solution:
def isPalindrome(self, x: int) -> bool:
if x < 0:
return False
elif x == 0:
return True
elif x % 10 == 0:
return False
else:
generated_num = 0
while x > generated_num:
generated_num = generated_num * 10 + x % 10
x = x // 10
return generated_num == x or (generated_num // 10) == x
解法性能:
解法分析:
首先,有一些特例可以直接判断,比如x为负数的话,因为负号的原因,直接可以返回False;如果x为0,则直接返回True;最后,如果x的最后一位为0,则直接返回False(因为除了0以外,x的最高位不会是0,所以无法和这个最后一位相等)。
接着,因为x的范围是:
− 2 31 < = x < = 2 31 − 1 -2^{31} <= x <= 2^{31}-1 −231<=x<=231−1
所以,如果x为
− 2 31 -2^{31} −231
则反转后会超过上限。为了避免这种情况的发生,我们可以反转一半进行判断。那么,我们是如何将输入的整数x反转一半的呢?
我们定义反转后的数为”generated_num”并初始化为0,然后通过下面的方式进行反转:
generated_num = generated_num * 10 + x % 10
x = x // 10
即”generated_num”不断先往前进一位(自身乘以10),然后加上x的最后一位(x除以10的余数),最后,x更新为它被除以10后的商。
因为我们已经将x ≤ 0的部分处理过了,所以剩下的所有x的情况,其位数分为两种情况:奇数和偶数。对于奇数的情况,我们以回文数12321为例,只要反转到反转后的数为123,就反转了一半了;接着,我们以非回文数12345为例,同样,只要反转到反转后的数为543,也反转了一半了。这时,反转后的数generated_num(比如543)是大于此时的x(比如12)。即对于奇数的情况,只要反转后的数大于此时的x,我们就可以停止反转,并且判断是否为回文数了。
同样道理,对于偶数的情况,我们以回文数1221为例,只要反转后的数为12,就反转了一半;接着,我们以非回文数1212为例,同样,只要反转后的数为21,也反转一半了。如果再反转一位,则反转后的数大于此时的x。此时,我们可以判断反转后的数是否和此时的x相等,若相等,则为回文数;若反转后的数更大,则退出反转,进行判断。
所以,我们停止反转的条件就是反转后的数generated_num大于等于此时的x。即对应代码中的:
while x > generated_num:
最后,退出反转后,我们进行判断,如果反转后的数等于此时的x,说明原本输入的整数x含有偶数个位数,且x为回文数。对应的代码如下所示:
generated_num == x
如果反转后的数去掉最后一位等于此时的x,则说明原本输入的整数x含有奇数个位数,且x为回文数。对应的代码如下所示:
(generated_num // 10) == x
其余的情况都不是回文数。