一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第10天,点击查看活动详情。
前言
笔者除了大学时期选修过《算法设计与分析》和《数据结构》还是浑浑噩噩度过的(当时觉得和编程没多大关系),其他时间对算法接触也比较少,但是随着开发时间变长对一些底层代码/处理机制有所接触越发觉得算法的重要性,所以决定开始系统的学习(主要是刷力扣上的题目)和整理,也希望还没开始学习的人尽早开始。
系列文章收录《算法》专栏中。
问题描述
给你一个 32 位的有符号整数 x ,返回将 x 中的数字部分反转后的结果。
如果反转后整数超过 32 位的有符号整数的范围 [−2^31, 2^31 − 1] ,就返回 0。
假设环境不允许存储 64 位整数(有符号或无符号)。
示例 1:
输入:x = 123
输出:321
示例 2:
输入:x = -123
输出:-321
示例 3:
输入:x = 120
输出:21
示例 4:
输入:x = 0
输出:0
提示:
- -2^31 <= x <= 2^31 - 1
剖析
暴力破解
拿到题的第一反应是:
- 如果是0就直接返回0。
- 如果是负数需要判断是否为最小负数,如果是就直接返回0。(因为后面需要统一转成正数,Integer.MIN_VALUE取反加一后还是负数,正好反转也超过了限制所以直接返回0)
- 标记是正数还是负数,统一按照正数处理,转成字符串进行反转。
- 字符串反转之后,转成数字(反转后转数字可能溢出,直接捕获NumberFormatException异常返回0即可),数字根据第三步标记的正负数进行还原正负数。
package com.study.algorithm.math;
public class ReverseNum {
public static int reverse(int x) {
int result = 0;
if (x == 0 || x == Integer.MIN_VALUE) {
return result;
}
boolean isNegative = x < 0 ? true : false;
StringBuilder stringBuilder;
if (isNegative) {
stringBuilder = new StringBuilder((~x + 1) + "");
} else {
stringBuilder = new StringBuilder(x + "");
}
Integer i;
try {
i = new Integer(stringBuilder.reverse().toString());
} catch (NumberFormatException e) {
return result;
}
result = isNegative ? ~i + 1 : i;
return result;
}
public static void main(String[] args) {
System.out.println((reverse(Integer.MIN_VALUE)));
}
}
上面的代码是通过了,执行用时2ms,内存消耗39MB,效率不是很理想,时间消耗在于整数转字符串、字符串反转、字符串转数字。
数学
题解中的方式,使用到了%10得到最后一位,/10消除最后一位,这样就能实现反转。需要注意的是防止溢出,% /是不会产生的,防止溢出可以在产生的过程中检查是否小于Integer.MIN_VALUE / 10或者大于Integer.MAX_VALUE / 10。不要用乘法会导致检查过程中溢出。
时间复杂度为O(logx),空间为O(1)。
代码
public static int reverse(int x) {
int result = 0;
while (x != 0) {
if (result > Integer.MAX_VALUE / 10 || result < Integer.MIN_VALUE / 10) {
return 0;
}
int digit = x % 10;
x = x / 10;
result = result * 10 + digit;
}
return result;
}