2021年04月14日 周三 天气晴 【不悲叹过去,不荒废现在,不惧怕未来】
1. 题目简介
2. 题解
2.1 计算首尾数值进行比较
刚开始的思路是,先计算位数,然后根据位数计算首尾数值,进行比较。
class Solution {
public:
bool isPalindrome(int x) {
if(x<0) return false;
int tmp = x, n = 0;
while(tmp){
tmp /= 10;
++n;
}
int a = x, b = x, cnt = n;
int beg = 0, end = 0;
for(int i=0;i<n/2;++i){
beg = a / pow(10,cnt-1);
end = b % 10;
if(beg!=end){
return false;
}
a -= beg * pow(10,cnt-1);
b /= 10;
--cnt;
}
return true;
}
};
乍一看,我还以为这种方法和官方题解一样,也是 O(logn) 的时间复杂度,毕竟提交也通过了。但是后来我转念一想,第二个循环中用到了 pow 函数,就算 pow 的时间复杂度当作 O(logn) ,总的时间复杂度也是 O(log(n!)) 。之所以提交通过了,可能是编译器对 自带的 pow 函数进行优化了吧(pow 函数的源码十分复杂,具体的时间复杂度是多少我也没有深究)。
2.2 反转一半的数字(掌握)
官方题解是真正的 O(logn) ,思路比较巧妙:在计算后部分数字的同时,不断缩小前部分数字,直到前部分数字小于等于后部分数字,然后根据前部分数字和后部分数字的大小是否相等判断最终结果(奇数特殊考虑)。
class Solution {
public:
bool isPalindrome(int x) {
// 特殊情况:
// 如上所述,当 x < 0 时,x 不是回文数。
// 同样地,如果数字的最后一位是 0,为了使该数字为回文,
// 则其第一位数字也应该是 0
// 只有 0 满足这一属性
if (x < 0 || (x % 10 == 0 && x != 0)) {
return false;
}
int revertedNumber = 0;
while (x > revertedNumber) {
revertedNumber = revertedNumber * 10 + x % 10;
x /= 10;
}
// 当数字长度为奇数时,我们可以通过 revertedNumber/10 去除处于中位的数字。
// 例如,当输入为 12321 时,在 while 循环的末尾我们可以得到 x = 12,revertedNumber = 123,
// 由于处于中位的数字不影响回文(它总是与自己相等),所以我们可以简单地将其去除。
return x == revertedNumber || x == revertedNumber / 10;
}
};
参考文献
https://leetcode-cn.com/problems/palindrome-number/solution/hui-wen-shu-by-leetcode-solution/