# 反转数字(7)
# 题目
给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
# 示例
输入: 123
输出: 321
输入: -123
输出: -321
输入: 120
输出: 21
s
# 注意
假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−2^31, 2^31 − 1]
。请根据这个假设,如果反转后整数溢出那么就返回 0
。
# 算法
# 暴力法
原数字 => 字符串 => 判断是否需要取出符号 => 数组 => 反转数组 => 是否需要在头部添加负号 => 拼接字符串 => 转换数字 => 判断是否溢出 => 返回结果
export const reverse = (x) => {
const s = x.toString();
const arr = s.split("");
let minusSign = "";
if (arr[0] === "-") {
minusSign = arr.shift();
}
arr.reverse();
if (minusSign === "-") {
arr.unshift(minusSign);
}
const n = Number.parseInt(arr.join(""));
if (n >= -(2 ** 31) && n <= 2 ** 31 - 1) {
return n;
}
return 0;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 模拟push和pop
类似反转字符串
的方法,将原数字最后一位取出,放入新数字的最后一位
因为数字没有类似数组的pop
和push
方法,所以我们利用数学运算模拟出这两个方法的效果
- 类似
pop
取出原数字的最后一位:x%10; ~~(x/10)
- 类似
push
将取出数字加入新数字最后一位:res*10+pop
在放入新数字之前,判断结果是否溢出,溢出则直接返回0
export const reverse_2 = (x) => {
const INT_MAX = 2 ** 31 - 1;
const INT_MIN = -(2 ** 31);
let res = 0;
while (x !== 0) {
const temp = x % 10;
x = ~~(x / 10);
if (res > (INT_MAX - temp) / 10) return 0;
if (res < (INT_MIN - temp) / 10) return 0;
res = res * 10 + temp;
}
return res;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
# JS 位运算
类似第二种方法:
x|0
进行位运算可以返回一个带符号的32位整数
如果res|0!==res
则说明res溢出了
export const reverse = (x) => {
let res = 0;
while (x !== 0) {
res = res * 10 + (x % 10);
x = (x / 10) | 0;
}
if ((res | 0) === res) {
return res;
}
return 0;
};
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
# 优化算法二
其实是不是回文数,无需全部反转后判断,而是只反转数字的一半就可以判断
如何判断已经反转了一般数字并跳出循环是关键:当被反转的原数字小于等于反转后数字时,说明已经反转了一半了,所以循环条件是被反转数>翻转数
最后是回文数
的条件是:翻转数和被反转数相等(数字长度是偶数)、或者翻转数相等和被反转数去掉一位后相等(数字长度是奇数)
排除临界条件:
- 负数
- 除
0
以外末尾为0
的数字
export const isPalindrome = (x) => {
if (x < 0 || (x !== 0 && x % 10 === 0)) return false;
let palindrome = 0;
while (palindrome < x) {
palindrome = palindrome * 10 + (x % 10);
x = ~~(x / 10);
}
return x === palindrome || x === ~~(palindrome / 10);
};
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9