1. 题目
给你一个 32 位的有符号整数 x
,返回将 x
中的数字部分反转后的结果。
如果反转后整数超过 32 位的有符号整数的范围 [ − 2 31 , 2 31 − 1 ] [−2^{31}, 2^{31} − 1] [−231,231−1] ,就返回 0。
假设环境不允许存储 64 位整数(有符号或无符号)。
示例 1:
输入:x = 123
输出:321
示例 2:
输入:x = -123
输出:-321
示例 3:
输入:x = 120
输出:21
示例 4:
输入:x = 0
输出:0
提示:
- − 2 31 < = x < = 2 31 − 1 -2^{31} <= x <= 2^{31} - 1 −231<=x<=231−1
2. 思路及代码实现(Python)
2.1 数学方法
记 rev \textit{rev} rev 为翻转后的数字,为完成翻转,我们可以重复「弹出」 x x x 的末尾数字,将其「推入」 rev \textit{rev} rev 的末尾(最后推入的数字在 x x x 当中是最高位),直至 x x x 为 0 0 0,此时就完成了数字的反转,反转的操作如下:
rev = 0
while True:
# 弹出x的末尾数字
digit = x % 10
# x去掉最后一位
x //= 10
# 将x的最后一位压入到rev的末尾
rev = rev * 10 + digit
if x == 0:
break
return rev
题目中除了反转,还需要判断反转后的数字是否在
−
2
31
,
2
31
-2^{31}, 2^{31}
−231,231 之间,因此需要在将 digit
推入 rev
时判断是否满足该范围,若不满足则返回 0。然而,题目给出了另一个限制就是:不允许使用64位整数,如果 digit
推入 rev
超过范围了,则我们先推入后判断的这个思路,就会破坏题目的要求,因此不能直接按照该条件比较大小。
一个思路是,通过公式逆推,判断 digit
和 rev
的取值在什么范围下,推入后的结果满足要求,或者不满足要求。考虑
x
>
0
x>0
x>0的情况,记
I
N
T
_
M
A
X
=
2
31
−
1
=
2147483647
INT\_MAX=2^{31}-1=2147483647
INT_MAX=231−1=2147483647,显然可得:
I N T _ M A X = ⌊ I N T _ M A X 10 ⌋ × 10 + 7 INT\_MAX=\Big\lfloor \frac{INT\_MAX}{10}\Big\rfloor \times 10+7 INT_MAX=⌊10INT_MAX⌋×10+7
得到:
r e v × 10 + d i g i t ≤ I N T _ M A X rev\times 10 +digit \leq INT\_MAX rev×10+digit≤INT_MAX
⇒ r e v × 10 + d i g i t ≤ ⌊ I N T _ M A X 10 ⌋ × 10 + 7 \Rightarrow rev\times 10 +digit\leq \Big\lfloor \frac{INT\_MAX}{10}\Big\rfloor\times 10+7 ⇒rev×10+digit≤⌊10INT_MAX⌋×10+7
⇒ ( r e v − ⌊ I N T _ M A X 10 ⌋ ) × 10 ≤ 7 − d i g i t \Rightarrow (rev-\Big\lfloor \frac{INT\_MAX}{10}\Big\rfloor)\times10\leq7-digit ⇒(rev−⌊10INT_MAX⌋)×10≤7−digit
这里的 r e v rev rev 和 ⌊ I N T _ M A X 10 ⌋ \Big\lfloor \frac{INT\_MAX}{10}\Big\rfloor ⌊10INT_MAX⌋ 均是整数,而 0 ≤ d i g i t ≤ 9 0\leq digit\leq 9 0≤digit≤9,易知:
- 当 r e v > ⌊ I N T _ M A X 10 ⌋ rev \gt \Big\lfloor \frac{INT\_MAX}{10}\Big\rfloor rev>⌊10INT_MAX⌋,则上述不等式的左端项至少为 10,而右端项最大为 7,显然不等式不成立;
- 当 r e v = ⌊ I N T _ M A X 10 ⌋ rev = \Big\lfloor \frac{INT\_MAX}{10}\Big\rfloor rev=⌊10INT_MAX⌋,上述不等式左端项为0,右端项取值范围为 [ − 2 , 7 ] [-2, 7] [−2,7],不等式存在成立的可能;然而,如果等式不成立,说明推入的 d i g i t digit digit 是 x x x 的最高位,因此此时 d i g i t ≤ 2 digit\leq 2 digit≤2,此时等式成立,这个相悖的条件和结果,说明在该情况下,等式不存在不成立的可能;
- 当 r e v < ⌊ I N T _ M A X 10 ⌋ rev \lt \Big\lfloor \frac{INT\_MAX}{10}\Big\rfloor rev<⌊10INT_MAX⌋,上述不等式左端项最大为-10,而右端项的范围是 [ − 2 , 7 ] [-2,7] [−2,7],因此,不等式必定成立。
综上可知,当 r e v ≤ ⌊ I N T _ M A X 10 ⌋ rev \leq \Big\lfloor \frac{INT\_MAX}{10}\Big\rfloor rev≤⌊10INT_MAX⌋时,不等式成立。 x = 0 x=0 x=0,则返回0,而 x < 0 x\lt0 x<0的情况的推导过程与上类似。最终得到,推入末尾数之后是否满足范围要求,可以更改为判断下式是否成立,若不成立,则说明推入末尾数也会超出既定范围,则返回0。
⌊ − 2 31 10 ⌋ ≤ r e v ≤ ⌊ 2 31 − 1 10 ⌋ \Big\lfloor \frac{-2^{31}}{10}\Big\rfloor \leq rev \leq \Big\lfloor \frac{2^{31}-1}{10}\Big\rfloor ⌊10−231⌋≤rev≤⌊10231−1⌋
此时,算法的时间复杂度为: O ( l o g ∣ x ∣ ) O(log∣x∣) O(log∣x∣)。翻转的次数即 x x x 十进制的位数。空间复杂度为: O ( 1 ) O(1) O(1)。
class Solution:
def reverse(self, x: int) -> int:
INT_MIN, INT_MAX = -2**31, 2**31 - 1
rev = 0
while x != 0:
# INT_MIN 也是一个负数,不能写成 rev < INT_MIN // 10
if rev < INT_MIN // 10 + 1 or rev > INT_MAX // 10:
return 0
digit = x % 10
# Python3 的取模运算在 x 为负数时也会返回 [0, 9) 以内的结果,因此这里需要进行特殊判断
if x < 0 and digit > 0:
digit -= 10
# 同理,Python3 的整数除法在 x 为负数时会向下(更小的负数)取整,因此不能写成 x //= 10
x = (x - digit) // 10
rev = rev * 10 + digit
return rev
执行用时:48 ms
消耗内存:17.06 MB
参考来源:力扣官方题解