第二题 Reverse Integer
从今天开始记录,学习总有个规律和过程,慢慢来,人生大部分遇到的问题都可以从前人的经验中找到答案,多看看书
题目描述:
Reverse digits of an integer.
Example1: x = 123, return 321
Example2: x = -123, return -321The input is assumed to be a 32-bit signed integer. Your function should return 0 when the reversed integer overflows
提示里面说是
1、首先要排除数字末尾的零干扰 如120 翻转之后就变为21
2、其次是溢出问题,32位整数会有表达限制,数据范围
拿到这道题首先的思路肯定是翻转数字的算法,朴素的方法,取出各个数位然后保存到一个数组中然后倒序输出数组即可
while(x!=0){
temp[size]=x%10;
x/=10;
size++;
}
取出的时候也用相同的办法
for(int i=0;i<size;i++)
{
result *= 10;
result += temp[i];
}
这种算法最终结果是按照数组对应元素的下标进行加权最终得到的结果,所以第一个问题可以解决,也不必担心正负号问题。
关键的问题在于判断溢出,首先要判断输入数据的范围,输入数据是标准的32位Int型整数,范围是-2147483648~2147483647,输出也是int型。由于输入的限制,找不到一个数翻转之后为2147483647,所以不必担心数据能够到表达范围的极限。
最开始我过分担心这个问题,还引入了判断输入数的正负来决定最终比较用的是Integer.MAX_VALUE还是Integer.MIN_VALUE,最终发现这是没有必要的,一切变化都是建立在输入自变量的基础上的,没有必要处理离开自变量范围的数据。
判断溢出,本身我的想法是溢出时数据有效位数已经到达了10位,在程序中判断一旦数字位数到达了十位,便把相应的数组和代表数字最大值的数组比较,按位相互比较,判断该数字和整数范围之间的关系。此时还有一个问题,由于输入数组中有正数有负数,所以判断时的正负还要判断。
if(size>=10)
{
int compare[10],num=0;
unsigned int a =0;
int MAX = (~a)/2;
if(flag)
MAX = -MAX;
while(MAX!=0)
{
compare[num]=MAX%10;
MAX/= 10;
num++;
}
if(flag)
{
for(int i=0;i<10;i++)
{
if(temp[i]<compare[9-i])
return 0;
if(temp[i]>compare[9-i])
break;
if(temp[i]==compare[9-i])
continue;
}
}
for(int i=0;i<10;i++)
{
if(temp[i]>compare[9-i])
return 0;
if(temp[i]<compare[9-i])
break;
if(temp[i]==compare[9-i])
continue;
}
}
按照这个思路写是没什么大问题,算法的复杂度由于输入数据的范围限制也不会很高,但是始终显得不是很优雅,于是参考别人的方法。
整个过程中可以优化的地方有两个
* 一个是对溢出的判断显得太过繁琐,可以直接用数字的运算进行判断而无需担心运算的过程中数据溢出,这就牵涉到怎么写这个运算的问题了。
* 二是没有必要使用使用临时数组来进行中间的存储,使用得当,所有的过程可以在一次循环中解决,这样既提升了效率又显得非常优雅,要学的地方还有很多。
class Solution{
public:
int reverse(int x){
unsigned int a = 0;
int MAX_VALUE = (~a)/2;
int MIN_VALUE = -(MAX_VALUE+1);
//temp表示每次取出来的数位值
int result =0,temp = 0;
bool flag =false;
//取绝对值 标记正负
if(x<0){
flag = true;
x = -x;
}
while(x!=0){
temp = x%10;
if(result!=0){
if(((MAX_VALUE-temp)/result <10)||((MIN_VALUE+temp)/result>-10))
return 0;
}
result = result*10+temp;
x/=10;
}
if(flag)
result = -result;
return result;
}
};