[LeetCode] 7.整数反转

一、题目描述

给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。

如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1] ,就返回 0。

假设环境不允许存储 64 位整数(有符号或无符号)。

示例 1:

输入:x = 123
输出:321

示例 2:

输入:x = -123
输出:-321

示例 3:

输入:x = 120
输出:21

示例 4:

输入:x = 0
输出:0

提示:

  • -231 <= x <= 231 - 1

二、题解

r e v rev rev 为翻转后的数字,为完成翻转,我们可以重复「弹出」 x x x 的末尾数字,将其「推入」 r e v rev rev 的末尾,直至 x x x 为 0。

要在没有辅助栈或数组的帮助下「弹出」和「推入」数字,我们可以使用如下数学方法:

// 弹出 x 的末尾数字 digit
digit = x % 10
x /= 10

// 将数字 digit 推入 rev 末尾
rev = rev * 10 + digit

题目需要判断反转后的数字是否超过 32 位有符号整数的范围 [ − 2 31 , 2 31 − 1 ] [-2^{31},2^{31}-1] [231,2311],例如 x = 2123456789 x=2123456789 x=2123456789 反转后的 r e v = 9876543212 > 2 31 − 1 = 2147483647 rev=9876543212>2^{31}−1=2147483647 rev=9876543212>2311=2147483647,超过了 32 位有符号整数的范围。

因此我们需要在「推入」数字之前,判断是否满足

− 2 31 ≤ r e v ⋅ 10 + d i g i t ≤ 2 31 − 1 −2^{31}≤rev⋅10+digit≤2^{31}−1 231rev10+digit2311
若该不等式不成立则返回 000。

但是题目要求不允许使用 64 位整数,即运算过程中的数字必须在 32 位有符号整数的范围内,因此我们不能直接按照上述式子计算,需要另寻他路。

考虑 x > 0 x>0 x>0 的情况,记 I N T M A X = 2 31 − 1 = 2147483647 INT_MAX=2^{31}−1=2147483647 INTMAX=2311=2147483647,由于
INT_MAX = ⌊ INT_MAX 10 ⌋ ⋅ 10 + ( INT_MAX   m o d   10 ) = ⌊ INT_MAX 10 ⌋ ⋅ 10 + 7 \begin{aligned} \textit{INT\_MAX}&=\lfloor\dfrac{\textit{INT\_MAX}}{10}\rfloor\cdot10+(\textit{INT\_MAX}\bmod10)\\ &=\lfloor\dfrac{\textit{INT\_MAX}}{10}\rfloor\cdot10+7 \end{aligned} INT_MAX=10INT_MAX10+(INT_MAXmod10)=10INT_MAX10+7

则不等式

rev ⋅ 10 + digit ≤ INT_MAX \textit{rev}\cdot10+\textit{digit}\le\textit{INT\_MAX} rev10+digitINT_MAX

等价于

r e v ⋅ 10 + d i g i t ≤ ⌊ I N T _ M A X 10 ⌋ ⋅ 10 + 7 rev⋅10+digit≤⌊INT\_MAX10⌋⋅10+7 rev10+digitINT_MAX1010+7

移项得

( r e v − ⌊ I N T _ M A X 10 ⌋ ) ⋅ 10 ≤ 7 − d i g i t (rev−⌊INT\_MAX10⌋)⋅10≤7−digit (revINT_MAX10⌋)107digit

讨论该不等式成立的条件:

r e v > ⌊ I N T _ M A X 10 ⌋ rev>⌊INT\_MAX10⌋ rev>INT_MAX10,由于 d i g i t ≥ 0 digit≥0 digit0,不等式不成立。 若 r e v = ⌊ I N T _ M A X 10 ⌋ rev=⌊INT\_MAX10⌋ rev=INT_MAX10,当且仅当 d i g i t ≤ 7 digit≤7 digit7 时,不等式成立。 若 r e v < ⌊ I N T _ M A X 10 ⌋ rev<⌊INT\_MAX10⌋ rev<INT_MAX10,由于 d i g i t ≤ 9 digit≤9 digit9,不等式成立。

注意到当 r e v = ⌊ I N T _ M A X 10 ⌋ rev=⌊INT\_MAX10⌋ rev=INT_MAX10 时若还能推入数字,则说明 x x x 的位数与 I N T _ M A X INT\_MAX INT_MAX 的位数相同,且要推入的数字 d i g i t digit digit x x x 的最高位。由于 x x x 不超过 I N T _ M A X INT\_MAX INT_MAX,因此 d i g i t digit digit 不会超过 I N T _ M A X INT\_MAX INT_MAX 的最高位,即 d i g i t ≤ 2 digit≤2 digit2。所以实际上当 r e v = ⌊ I N T _ M A X 10 ⌋ rev=⌊INT\_MAX10⌋ rev=INT_MAX10 时不等式必定成立。

因此判定条件可简化为:当且仅当 r e v ≤ ⌊ I N T _ M A X 10 ⌋ rev≤⌊INT\_MAX10⌋ revINT_MAX10 时,不等式成立。

x < 0 x<0 x<0 的情况类似,留给读者自证,此处不再赘述。

综上所述,判断不等式

− 2 31 ≤ r e v ⋅ 10 + d i g i t ≤ 2 31 − 1 −2^{31}≤rev⋅10+digit≤2^{31}−1 231rev10+digit2311
是否成立,可改为判断不等式

⌈ − 2 3 1 10 ⌉ ≤ r e v ≤ ⌊ 2 31 − 1 10 ⌋ ⌈\frac{−2^31}{10}⌉≤ rev ≤⌊\frac{2^{31}−1}{10}⌋ 10231rev102311
是否成立,若不成立则返回 0。

Python
 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
C++
int reverse(int x) 
{
    int rev = 0;
    while (x != 0) 
    {
        if (rev < INT_MIN / 10 || rev > INT_MAX / 10) 
        {
            return 0;
        }
        int digit = x % 10;
        x /= 10;
        rev = rev * 10 + digit;
    }
    return rev;
}
复杂度分析
  • 时间复杂度: O ( l o g ∣ x ∣ ) O(log∣x∣) O(logx)。翻转的次数即 x x x 十进制的位数。
  • 空间复杂度: O ( 1 ) O(1) O(1)

你可能感兴趣的:(LeetCode,leetcode,python,算法,C++)