来源:LeetCode
难度:简单
问题详情:
给你一个整数 x ,如果 x 是一个回文整数,返回 true ;否则,返回 false 。
回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
输入:x = 121
输出:true
输入:x = -121
输出:false
解释:从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。
输入:x = 10
输出:false
解释:从右向左读, 为 01 。因此它不是一个回文数
进阶:你能不将整数转为字符串来解决这个问题吗?
从给出的示例可以看出:
同时,也可以想到:
在真正开始介绍各种算法前,先以表格形式展示各自的时间复杂度和空间复杂度。
| 算法 | 时间复杂度 | 空间复杂度 |
|---|---|---|
| 字符串法 | 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) |
根据进阶要求的限制,我们反而能够很容易想到这个解法。将数字转换为字符串列表,然后反转列表,再转换为数字对比是否与反转前相等即可。
同时将分析得到的三种情况先做一个返回。
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))
不使用字符串的前提下,我们就需要真的将数值反转过来对比。
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)
折半法其实是直接法的优化,因为其实我们并不需要将所有的位数都反转,而只需反转一半,然后对比是否与另一半未反转的相同即可。
举例来说,1221,我们只需反转后半部分的21为12,然后对比前半部分看是否一致。
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)