题目内容描述:
Determine whether an integer is a palindrome. Do this without extra space.
一般判断回文数字,会把它先转换成字符串然后用头尾两个指针扫描字符串判断即可。但是题目要求不能申请多余的空间,也就是不能转换成字符串,这个难度就上来了,字符操作变成了数字操作,需要更多的技巧。
首先按照回文的定义,负数由于负号的存在肯定不是回文数字
其次只有一个数位的数字即0~9一定是回文数字
最后对于一般的数字我们直接将数字翻转,然后比较翻转前后的两个数字是否大小相等即可
针对数字的翻转用的算法比较巧妙:
int reverseNum = 0;
while(num!=0){
reverseNum = reverseNum*10 + num%10;
num /= 10;
}
拆分数位时,一般会不断模10取值,这个时候取出的数字是倒序的,翻转时相应数位的权值会颠倒恰好就可以递归乘10,能够得到翻转的结果。
但是
到这里还没有完,一旦牵涉到数字运算就必须考虑到数字的溢出问题,如果数据溢出,还能不能够判断这个回文数字呢?假如一个数字翻转之后的数字溢出了,那肯定不是这个数字原来的值了,这个时候不就没办法判断了吗?
仔细推理一下
输入的变量值是一个正常的int型整数,-2147483648~2147483647的取值范围,如果它真的溢出了说明输入的数值是一个十位数,然后末尾的最后一个数字大于2,在这种情况下首尾数位的数字不相等,肯定不是回文数字,所以一旦溢出,一定不是回文数字。
判断溢出的办法就比较简单了,如果在一个增加数值的情况下,这个数字反而比原来的数字还小,那就证明发生了溢出。
具体题解代码如下:
class Solution{
public:
bool isPalindrome(int x){
if(x<0){
return false;
}else{
if(x<=9){
return true;
}else{
int reverse_X=0,temp=x,Judge;
while(temp!=0){
Judge = reverse_X;
reverse_X=reverse_X*10+temp%10;
if(reverse_X<Judge){
return false;
}
temp/=10;
}
if(reverse_X==x)
return true;
else
return false;
}
}
}
};
这个题在最开始写时,没有好好考虑溢出与判断回文之间的关系,只是想要在一个数字上实现相当于字符串的操作,不断地去掉提取出输入数字的首尾数位进行比较,然后去掉头尾数字,再进行接下来的比较。
这个时候问题明显变得更复杂了,去掉尾部数字除10即可,没有问题,但是在去掉头部数字时有了问题,如果第二个数位的数字为0,去掉头部数字之后第二个数位就会消失。这个时候就出现了数字和字符串的不同,这个时候证明之前的想法肯定是不对的,要推倒重来。
不能死钻牛角尖,目的是解决问题,不是修补错思路上的漏洞。
然后问题就来到了下一个阶段,既然在数字上进行原地操作很困难,就放弃对数字的调整。把头尾数位数字看做是指针,问题就变成了如何取出指针对应数位的数字,这个时候就可以用到上面的思考,取出末尾数位的数字是最可靠的,那就尾部截断输入的数字,使要求的数位在末尾,随机模10 即可。
另一种解法代码如下:
class Solution{
public:
bool isPalindrome(int x) {
//负数 一定不是回文数字 这个时候把它看成字符串
if(x<0){
return false;
}
//i j 分别指向数字头尾的指针
int i,j,top_digit,bottom_digit,temp,digitSum=0;
temp = x;
while(temp!=0)
{
digitSum++;
temp/=10;
}
i = digitSum-1,j=0;
while(i>j)
{
top_digit=(int)(x/pow(10,i));
top_digit=top_digit%10;
bottom_digit=(int)(x/pow(10,j));
bottom_digit=bottom_digit%10;
cout<<"top_digit = "<<top_digit<<" "<<"bottom_digit = "<<bottom_digit<<endl;
if(top_digit!=bottom_digit)
return false;
i--;
j++;
}
//错误写法 针对数字的原地操作 思路错了
/*while(flag){
top_digit = x/pow(10,i);
bottom_digit = x%10;
if(top_digit!=bottom_digit){
return false;
}
x/=10;
i--;
x = x-(int)((pow(10,i))*top_digit);
if(x>=0&&x<=9)
flag=0;
}*/
return true;
}
};
总的来说,第一种解法是比较优雅,充分利用了数字的特性,第二种解法是换了个方式模拟一个字符数列,算是取巧了。这道题本身没有太高的立意,只是一般的考验逻辑的题。