0007. 整数反转 Reverse Integer

问题描述

这是一个数学问题. 它考察的知识有这几个方面:

  1. 如何从十进制的整数中提取出各个位的值
  2. 如何从各个位的值重新组装一个整数
  3. 如何处理整数边界溢出的问题

接下来我们分别来说说.

从十进制的整数中提取出各个位的值

要使用 除10 的操作, 进行十进制的右移.

#![allow(unused)]
fn main() {
let mut x = 1234;
while x != 0 {
  println!("unit value: {}", x % 10);
  x /= 10;
} 
}

看图:

get-unit-digit

重新组装整数

如何从各个位的值重新组装一个整数? 使用相反的操作, 乘10, 进行十进制的左移操作.

#![allow(unused)]
fn main() {
let mut number = 0;
let bits = &[4, 3, 2, 1];
for bit in bits {
  number = number * 10 + bit;
}
println!("number: {number}");
}

看图:

assemble-integer

整数溢出

如何处理整数边界溢出的问题? 在组装新的整数时, 可以让当前的值 *10 后与 i32::MAX .. i32::MIN 进行比较, 看在不在这个范围内.

number > i32::MAX / 10 || number < i32::MIN / 10

integer-in-range

要注意的一点是, 不能使用 number * 10 > i32::MAX 这样的写法, 因为 number * 10 本身就可能溢出了!

基于以上3点, 编写出最终的代码:

#![allow(unused)]
fn main() {
#[allow(clippy::manual_range_contains)]
pub fn reverse(x: i32) -> i32 {
    let mut x = x;
    let mut rev = 0;

    // x == 0 时, 表示它的所有整数进位值都被提取完了.
    while x != 0 {
        // 检查 rev 在添加新的个位值后是否会溢出
        if rev > i32::MAX / 10 || rev < i32::MIN / 10 {
            return 0;
        }
        // 从 x 中提取出个位的值, 然后作为新的个位数值, 添加到 rev 上.
        rev = rev * 10 + x % 10;
        x /= 10;
    }
    rev
}
}