01数字反转.7
https://leetcode-cn.com/problems/reverse-integer/
1.Comprehensive两种理解思路
理解1:理解为逆序输出
理解2:理解为首尾交换
2. Choose数据结构及算法思维选择
方案1:逆序输出(暴力解法)
- 整数转字符串,字符串转数组
- 数据结构:字符数组
- 算法思维:遍历
方案2:首尾交换(优化解法)
- 整数转字符串,字符串转数组
- 数据结构:字符数组
- 算法思维:遍历
数据结构-数组
- 数组容量固定不变
- 使用连续的物理空间存取数据
- O(1)复杂度读取任意元素
3.Code基本解法及编码实现
解法1:暴力解法
- 整数转字符串,再转为字符数组
- 反向遍历字符数组,并将元素存到新数组中
- 将新数组转为字符串,再转为整数输出
解法1:暴力解法边界和细节问题
-
边界问题:
-
数组索引越界
-
数值溢出边界:溢出则返回0
-
-
细节问题:
-
首位不为0
-
符号位处理
-
我写的解法1:char数组逆序
class Solution {
public int reverse(int x) {
int signed = x > 0 ? 1 : -1;
long number = x;//这里转为long,避免溢出,
number = Math.abs(number);
//1. 整数转字符串,字符串转字符数组
String str = String.valueOf(number);
char[] oldCharArray = str.toCharArray();
char[] newReveredCharArray = new char[oldCharArray.length];
//2. 逆序输出字符数组
for (int i = oldCharArray.length - 1; i >= 0; i--) {
newReveredCharArray[oldCharArray.length - 1 - i] = oldCharArray[i];
}
//3. 字符数组转字符串,再转为整数
String reversedStr = String.valueOf(newReveredCharArray);
long unsignedResult = Long.parseLong(reversedStr);
long result = signed * unsignedResult;
if (result > Integer.MAX_VALUE || result < Integer.MIN_VALUE) {
result = 0;
}
return (int) result;
}
}
我写的解法2:StringBuffer的reverse API逆序
/**
* 使用StringBuffer的reverse API简化数组操作
*/
class Solution {
public int reverse(int x) {
int signed = x > 0 ? 1 : -1;
long number = x;//这里转为long,避免Integer.MIN_VALUE取反溢出
number = Math.abs(number);
//1. 整数转字符串,字符串转字符数组
String str = String.valueOf(number);
//3. 字符数组转字符串,再转为整数
String reversedStr = new StringBuffer(str).reverse().toString();
long unsignedResult = Long.parseLong(reversedStr);
long result = signed * unsignedResult;
if (result > Integer.MAX_VALUE || result < Integer.MIN_VALUE) {
result = 0;
}
return (int) result;
}
}
我写的解法3:另一种溢出判断
class Solution {
public int reverse(int x) {
int signed = x > 0 ? 1 : -1;
long number = x;//这里转为long
number = Math.abs(number);
//1. 整数转字符串,字符串转字符数组
String str = String.valueOf(number);
//3. 字符数组转字符串,再转为整数
String reversedStr = new StringBuffer(str).reverse().toString();
long unsignedResult = Long.parseLong(reversedStr);
long result = signed * unsignedResult;
if (result != (int) (result)) {//如果
result = 0;
}
return (int) result;
}
}
拉勾网给的解法:char数组逆序
class Solution {
/**
* 编写代码时,先编写主体代码
*/
public int reverse(int x) {
if (x == Integer.MIN_VALUE) {
// 整数类型最小值的绝对值 比 最大值的绝对值 大1
return 0; // 反转必然溢出,返回0
}
int sign = x > 0 ? 1 : -1; // 符号
x = x < 0 ? x * -1 : x; // 无论正负,都当成正数
// 1.整数转字符串,再转字符数组
String str = String.valueOf(x);
char[] chars = str.toCharArray();
// 2.反向遍历字符数组,并将元素存储到新数组中
int len = chars.length;
char[] array = new char[len];
for (int i = 0; i < len; i++) { // 遍历新数组
array[i] = chars[len - 1 - i];
}
// 3.将新数组转成字符串,再转成整数输出
long value = Long.valueOf(String.valueOf(array));
boolean b = value > Integer.MAX_VALUE || value < Integer.MIN_VALUE;
int result = b ? 0 : (int) value; // 数值越界:溢出则返回0
return result * sign; // 符号还原 }
}
}
时间复杂度与空间复杂度分析
时间复杂度:O(n)
- 将整数转成字符串O(n)
- 遍历字符数组O(n)
- O(n) +O(n)=O(2n)
- 忽略常数后:O(n)
空间复杂度:O(n)
- 一个字符串O(n)
- 一个新数组O(n)
- O(n) +O(n)=O(2n)
- 忽略常数后:O(n)
解法2:首尾交换
- 整数转字符串,再转为字符数组
- 遍历字符数组,数组内元素原地首尾交换
- 将新数组转为字符串,再转为整数输出
解法2:首尾交换边界和细节问题
- 边界问题
- 数组索引越界
- 数组为偶数,完成标志为start>end
- 数组为奇数,完成标志为start=end
- 所以边界条件为start<end
- 数值溢出边界:溢出则返回0
- 数组索引越界
- 细节问题
- 首尾不为0
- 符号处理
我写的解法1:char数组首尾交换
class Solution {
public int reverse(int x) {
int signed = x > 0 ? 1 : -1;
long number = x;//这里转为long
number = Math.abs(number);
//1. 整数转字符串,字符串转字符数组
String str = String.valueOf(number);
char[] charArray = str.toCharArray();
//2. 逆序输出字符数组
int startIndex = 0, endIndex = charArray.length - 1;
while (startIndex < endIndex) {
char temp = charArray[startIndex];
charArray[startIndex] = charArray[endIndex];
charArray[endIndex] = temp;
startIndex++;
endIndex--;
}
//3. 字符数组转字符串,再转为整数
String reversedStr = String.valueOf(charArray);
long unsignedResult = Long.parseLong(reversedStr);
long result = signed * unsignedResult;
if (result > Integer.MAX_VALUE || result < Integer.MIN_VALUE) {
result = 0;
}
return (int) result;
}
}
拉钩网给的解法:char数组首尾原地交换
class Solution {
/**
* 编写代码时,先编写主体代码
*/
public int reverse(int x) {
if (x == Integer.MIN_VALUE) {
// 整数类型最小值的绝对值 比 最大值的绝对值 大1
return 0; // 反转必然溢出,返回0
}
int sign = x > 0 ? 1 : -1; // 符号
x = x < 0 ? x * -1 : x; // 无论正负,都当成正数
// 1.整数转字符串,再转字符数组
String str = String.valueOf(x);
char[] chars = str.toCharArray();
int startIndex = 0, endIndex = chars.length - 1;
while (startIndex < endIndex) {
char temp = charArray[startIndex];
chars[startIndex] = chars[endIndex];
chars[endIndex] = temp;
startIndex++;
endIndex--;
}
// 3.将新数组转成字符串,再转成整数输出
long value = Long.valueOf(String.valueOf(chars));
boolean b = value > Integer.MAX_VALUE || value < Integer.MIN_VALUE;
int result = b ? 0 : (int) value; // 数值越界:溢出则返回0
return result * sign; // 符号还原 }
}
}
时间复杂度与空间复杂度
时间复杂度:O(n)
-
将整数转成字符串O(n)
-
遍历字符数组O(n)
-
O(n) +O(n)=O(2n)
-
忽略常数后:O(n)
空间复杂度:O(n)
- 一个字符串O(n)
- 一个新数组O(n)
- 绝对空间消耗降低:O(n)
4.Consider思考更优解及编码实现
- 剔除无效代码或优化空间消耗
- 操作是必须的吗?
- 数据结构是必须的吗?
- 寻找更好的算法思维
- 既然是整数,能否用数学思维?
- 借鉴其它算法
解法:数学思维解法
数学思维解法边界和细节问题
-
边界问题
-
什么时候结束?
-
从低位到高位处理,最高位结束
- 最高位/10==0
- 最高位%10==最高位
-
数值溢出边界:溢出则返回0
- 用long存放,溢出int则返回0
- 新整数补充最后一位前判断溢出
-
-
细节问题
- 同上
5. Code 最优解思路及编码实现
我写的解法1:数学思维法
class Solution {
public int reverse(int x) {
if (x == Integer.MIN_VALUE) {
//因为Integer.MIN_VALUE的绝对值必溢出,Integer.MAX_VALUE的绝对值不会溢出
return 0;
}
int signed = x > 0 ? 1 : -1;
long number = Math.abs(x);
long digit;
long unSignedResult = 0;
while (number != 0) {
digit = number % 10;
unSignedResult = unSignedResult * 10 + digit;
number = number / 10;
}
long result = unSignedResult * signed;
if (result > Integer.MAX_VALUE || result < Integer.MIN_VALUE) {
result = 0;
}
return (int) result;
}
}
时间复杂度与空间复杂度
时间复杂度:O(n)
• 遍历整数的每一位:O(n)
空间复杂度:O(1)
• 只需要一个整数变量O(1)
6.Change变形延伸
- (练习)对长整形数据进行反转
- (练习)对字符串进行反转
7.最优解通用解法
class Solution {
public long reverse(long x) {
long result = 0;
while (x != 0) {
if (result > Long.MAX_VALUE / 10 || result < Long.MIN_VALUE / 10) {
return 0;
}
long digit = x % 10;
x /= 10;
result = result * 10 + digit;
}
return result;
}
}