-
Notifications
You must be signed in to change notification settings - Fork 9
/
reverse_integer_checked_mul_overflow.rs
88 lines (80 loc) · 2.51 KB
/
reverse_integer_checked_mul_overflow.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
/*! https://leetcode.com/problems/reverse-integer/
& https://leetcode.com/problems/palindrome-number/
```text
https://twitter.com/ospopen/status/1322127786618748928
好喜欢Rust这种checked前缀的命名和设计,优雅解决了反转i32的溢出问题
不用像官方解答那样冗长的上限下限溢出判断,还有一堆数学公式推导出7和-8这两个晦涩难懂的临界值
与之相反的unchecked前缀的API都是unsafe的,例如unchecked_sub溢出就会运行时panicked at 'attempt to subtract with overflow'
```
*/
/// 注意Python/Ruby不能这么写(abs()),因为 Python -1整除10都等于-1(div_euclid),会陷入死循环
/// reverse_integer(-2147483648) may panic on debug build(because overflow-checks=true profile), but work good on release build
fn reverse_integer(x: i32) -> i32 {
/*
|| -> Option<i32> {
let mut ret = 0_i32;
while x.abs() != 0 {
ret = ret.checked_mul(10)?.checked_add(x%10)?;
x /= 10;
}
Some(ret)
}().unwrap_or(0)
*/
fn helper(mut n: i32) -> Option<i32> {
let mut ret = 0_i32;
while n.abs() != 0 {
ret = ret.checked_mul(10)?.checked_add(n % 10)?;
n /= 10;
}
Some(ret)
}
helper(x).unwrap_or_default()
}
// use std::ops::ControlFlow;
// fn reverse_integer_control_flow(mut n: i32) -> ControlFlow<i32, i32> {
// let mut ret = 0_i32;
// while n.abs() != 0 {
// ret = ret.checked_mul(10)?.checked_add(n % 10)?;
// n /= 10;
// }
// Controlo
// }
/// Beware of overflow when you reverse the integer
fn is_palindrome(x: i32) -> bool {
if x < 0 {
return false;
}
x == reverse_integer(x)
}
const fn is_palindrome_half_traverse(x: i32) -> bool {
if x < 0 || (x % 10 == 0 && x != 0) {
return false;
}
let mut num = x;
let mut rev = 0;
// 只会【遍历一半】,遍历到中间时rev和num的值就会相近
while rev < num {
rev = rev * 10 + num % 10;
num /= 10;
}
// dbg!((x, num, rev));
rev == num || num == (rev / 10)
}
#[test]
fn test_reverse() {
assert_eq!(reverse_integer(-123), -321);
}
#[test]
fn test_is_palindrome() {
const TEST_CASES: [(i32, bool); 5] = [
(121, true),
(-121, false),
(10, false),
(0, true),
(1_000_000_001, true),
];
for (input, expected) in TEST_CASES {
assert_eq!(is_palindrome(input), expected);
assert_eq!(is_palindrome_half_traverse(input), expected);
}
}