题目:
给你一个 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
思路一:拿到这道题目,不考虑其数学特性的话,我们将一整串数字直接转换为字符串,然后翻转整个字符串,再考虑边界条件,将字符串转换为 int 64 位,如果溢出 int 32 则返回零。
class Solution {
public int reverse(int x) {
int sign = 1;
String str = String.valueOf(x);
if (x < 0) {
sign = -1;
str = str.substring(1);
}
int len = str.length();
char[] reversedChar = str.toCharArray();
for (int i=0; i<len/2; i++) {
reversedChar[i] = str.charAt(len-1-i);
reversedChar[len-1-i] = str.charAt(i);
}
String reversedStr = new String(reversedChar);
long reversedLong = Long.valueOf(reversedStr).longValue() * sign;
if (reversedLong > (long) Integer.MAX_VALUE
|| reversedLong < (long) Integer.MIN_VALUE) {
return 0;
}
return Integer.valueOf(reversedStr) * sign;
}
}
整个代码涉及到的边界处理有些麻烦,首先是负数转换为字符串的符号问题,需要通过 sign 保存和恢复相应的正负号;其次在翻转负数字符串时需要去掉第一位符号位。其次是溢出的问题,需要转换为 long 长整型来进行判断。
时间复杂度:O(n) 转换字符串 + O(n) 处理符号 + O(n/2) 翻转字符串 + O(n) 长整型转换 + O(n) 整型转换
空间复杂度:O(n) 额外的 char 数组
思路二:上述思路一的时间空间复杂度有点惨不忍睹,所以我们还是要考虑整型数字的数学特性,那么如何翻转一个整数呢?我们想到不断地取数字串的位数基本公式是 digit = x % 10, x = x / 10,同时构建出这个反序数字串其实也很简单:reversedx = 0, reversedx = reversedx * 10 + digit。整个解题思路也就相应变得很明确:
class Solution {
public int reverse(int x) {
long reversedx = 0;
while(x != 0) {
reversedx = reversedx * 10 + x % 10;
x = x / 10;
}
return (int) reversedx == reversedx? (int)reversedx:0;
}
}
让我们再看一下复杂度,
时间复杂度:仅有一个 while 循环,为 O(n)
空间复杂度:仅仅需要一个长整型不断记录翻转后的数值,所以为 O(1)
思路三:当然上述解题还是借用了 long 长整型进行溢出的判断,更进一步,是否能够不借助其他类型,仅仅用整型进行判断呢?其实是可以的。当数字串 x>0 的时候,溢出意味着 reversedx * 10 + x % 10 > Integer.MAX_VALUE,等式变换后相当于 reversedx > (Integer.MAX_VALUE - x % 10) / 10。同理,当数字串 x<0 的时候,溢出意味着 reversedx * 10 + x % 10 < Integer.MIN_VALUE, 等式变换后为 reversedx < (Integer.MIN_VALUE - x % 10) / 10。实现后的代码如下:
class Solution {
public int reverse(int x) {
int reversedx = 0;
while(x!=0) {
reversedx = reversedx * 10 + x % 10;
x = x / 10;
if (x > 0 && reversedx > (Integer.MAX_VALUE - x % 10) / 10) {
return 0;
}
if (x < 0 && reversedx < (Integer.MIN_VALUE - x % 10) / 10) {
return 0;
}
}
return reversedx;
}
}
虽然思路一的代码实现的不尽人意,这里有几个 java 语言点仍旧值得注意:
字符串与数字的相互转换
数字转为字符串
- String的 ValueOf() 方法:
这是最常用的方法,对于包装类以及基本数据类型都适用。
Integer x = 123;
String str1 = String.valueOf(x);
- 直接拼接空字符串
String st2 = x + "";
- 包装类的 toString() 方法
注意该方法只适用于包装类,基本数据类型需要先调用包装类的 ValueOf() 方法再使用。
String str3 = x.toString();
字符串转数字
- 使用包装类的 ValueOf() 方法
通过包装类的 ValueOf() 方法,可以将字符串转换为想要的包装类,Byte、Short、Integer、Long、Float、Double 都有对应的 ValueOf() 方法。
Integer int1 = Integer.valueOf(str);
Double dou1 = Double.valueOf(str);
- 使用包装类的 parseXXX() 方法
通过包装类的 parseXXX() 方法,可以将字符串转换为想要的基本数据类型,同上都有相应的 parseXXX() 方法
int int2 = Integer.parseInt(str);
double dou2 = Double.parseDouble(str);
长整型同样囊括在上述方法之中
long long1 = Long.parseLong(str);
long long2 = Long.valueOf(str).longValue();