一、题目描述
判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
示例
- 示例 1:
- 输入:
x = 121
- 输出:
true
- 输入:
- 示例 2:
- 输入:
x = -121
- 输出:
false
- 解释:从左向右读为 -121 ,从右向左读为 121- ,因此它不是一个回文数。
- 输入:
- 示例 3:
- 输入:
x = 10
- 输出:
false
- 解释:从右向左读为 01 ,因此它不是一个回文数。
- 输入:
- 示例 4:
- 输入:
x = -101
- 输出:
false
- 输入:
二、解题思路与多方法实现
方法一:转换为字符串法
思路
将整数转换为字符串,然后比较字符串与其反转后的字符串是否相同。如果相同,则该整数是回文数;否则,不是回文数。
代码实现(Java)
public class PalindromeNumber {
public boolean isPalindrome(int x) {
// 将整数转换为字符串
String numStr = String.valueOf(x);
// 反转字符串
String reversedStr = new StringBuilder(numStr).reverse().toString();
// 比较原字符串和反转后的字符串
return numStr.equals(reversedStr);
}
}
代码解释
- 整数转字符串:使用
String.valueOf(x)
将整数x
转换为字符串numStr
。 - 字符串反转:利用
StringBuilder
的reverse()
方法将numStr
反转,得到reversedStr
。 - 结果比较:使用
equals()
方法比较numStr
和reversedStr
,如果相等则返回true
,否则返回false
。
方法二:数学方法(反转一半数字)
思路
通过数学运算反转整数的一半,然后将反转后的一半与原整数的前半部分进行比较。具体步骤如下:
- 负数不可能是回文数,直接返回
false
。 - 个位数为 0 且不为 0 的数也不是回文数,直接返回
false
。 - 不断地将整数的最后一位取出并添加到反转后的数中,同时将原数除以 10,直到反转后的数大于等于原数。
- 最后比较反转后的数与原数(当原数位数为偶数时)或者反转后的数除以 10 与原数(当原数位数为奇数时)是否相等。
代码实现(Java)
public class PalindromeNumberMath {
public boolean isPalindrome(int x) {
// 负数和个位数为 0 且不为 0 的数不是回文数
if (x < 0 || (x % 10 == 0 && x != 0)) {
return false;
}
int reversedNum = 0;
while (x > reversedNum) {
reversedNum = reversedNum * 10 + x % 10;
x /= 10;
}
// 当原数位数为偶数时,直接比较;当原数位数为奇数时,反转后的数除以 10 再比较
return x == reversedNum || x == reversedNum / 10;
}
}
代码解释
- 特殊情况判断:首先判断
x
是否为负数或者个位数为 0 且不为 0 的数,如果是则直接返回false
。 - 反转一半数字:使用
while
循环,在x > reversedNum
的条件下,不断将x
的最后一位取出并添加到reversedNum
中,同时将x
除以 10。 - 结果比较:当
x
不大于reversedNum
时,循环结束。此时如果原数位数为偶数,比较x
和reversedNum
是否相等;如果原数位数为奇数,比较x
和reversedNum / 10
是否相等。
方法三:逐位比较法
思路
通过不断获取整数的最高位和最低位进行比较,如果不相等则不是回文数。同时,去掉最高位和最低位,继续比较中间的数。
代码实现(Java)
public class PalindromeNumberDigitCompare {
public boolean isPalindrome(int x) {
if (x < 0) {
return false;
}
int div = 1;
// 找到能获取最高位的除数
while (x / div >= 10) {
div *= 10;
}
while (x > 0) {
int left = x / div;
int right = x % 10;
if (left != right) {
return false;
}
// 去掉最高位和最低位
x = (x % div) / 10;
div /= 100;
}
return true;
}
}
代码解释
- 负数判断:负数不是回文数,直接返回
false
。 - 找到最高位除数:使用
while
循环找到能获取x
最高位的除数div
。 - 逐位比较:在
x > 0
的条件下,通过x / div
获取最高位left
,通过x % 10
获取最低位right
,比较它们是否相等。如果不相等则返回false
。 - 去掉最高位和最低位:通过
(x % div) / 10
去掉最高位和最低位,同时将div
除以 100。 - 结果返回:如果循环结束都没有返回
false
,则说明是回文数,返回true
。
三、复杂度分析
时间复杂度
- 转换为字符串法:主要时间开销在于字符串反转,时间复杂度为 O ( n ) O(n) O(n),其中 n n n 是整数的位数。
- 数学方法(反转一半数字):只需要反转一半的数字,时间复杂度为 O ( l o g 10 n ) O(log_{10}n) O(log10n),其中 n n n 是整数的值。
- 逐位比较法:需要逐位比较,时间复杂度为 O ( l o g 10 n ) O(log_{10}n) O(log10n),其中 n n n 是整数的值。
空间复杂度
- 转换为字符串法:需要额外的字符串空间,空间复杂度为 O ( n ) O(n) O(n),其中 n n n 是整数的位数。
- 数学方法(反转一半数字):只使用了常数级的额外空间,空间复杂度为 O ( 1 ) O(1) O(1)。
- 逐位比较法:只使用了常数级的额外空间,空间复杂度为 O ( 1 ) O(1) O(1)。
四、总结
“回文数”这道简单题通过多种方法为我们展示了不同的解题思路。转换为字符串法简单直观,但需要额外的字符串空间;数学方法(反转一半数字)和逐位比较法在空间复杂度上更优,通过数学运算避免了字符串操作。在实际应用中,如果对空间要求不高,转换为字符串法是一种快速实现的方法;如果追求空间效率,数学方法则更为合适。希望通过对这道题的多种解法的学习,大家能在面对类似问题时,灵活选择最优的解决方案。