866. 回文素数
对于这道题,我们可以先将它拆分为两部分,回文和素数。
一. 首先我们先判断回文数,回文数的意思就是一个数的正向和反向的数字是一样的,例如:121,1221,12321等。
- 得到一个数的反向我们只需要通过 % 和 / 两个操作符,不断辗转,最后得到。
- 但是这种将一个整数整个反转的方法有点费时,毕竟我们只需判断,不需要计算。通过分析我们很容易可以看出,每个回文数都有一个对称轴可以将其对半划分,并且两边时一样得,所以我们可以反转后半部分,再与前半部分对比,如果一致则返回true。
- 但是我们还要考虑当位数为奇数的情况,按照上面的思路,如果时12321,循环结束后,我们会得到,reveredNumber = 123,n = 12,这种情况我们只需判断reveredNumber的前面两位数就行,所以我们的判断条件可以设为 if(reveredNumber == n || reveredNumber % 10 ==n)。
二.我们在考虑第二部分——素数
素数的定义是只有1和其本身这两个数是他的因子的数为素数。
判断一个数n是否为素数,我们只需在区间[2, n) 进行计算,如果在这个区间内还有其他的数可以整除n,则返回false。
但这样的计算量会很大,有没有什么方法能够对其进行优化呢?答案是肯定的。
我们不妨设x是n的一个因子,那么n / x 为一个整数,且 n / x也是n的一个因子,我们不妨设:
代码如下:
bool isPrime(int n) {
int i, sqrtn = sqrt(n + 1e-6);
if(n <= 1) {
return false;
}
for(i = 2; i <= sqrtn; ++i) {
if(n % i == 0) {
return false;
}
}
return true;
}
int primePalindrome(int n){
do{
//大于八位的数没有素数,所以直接返回100030001
if(n >= 10000000)return 100030001;
int x = n;
if(x % 10 == 0 && x != 0){
continue;
}
int reveredNumber = 0;
//判断是否为回文数
while(x > reveredNumber){
reveredNumber *= 10;
reveredNumber += x % 10;
x /= 10;
}
bool b = false;
if(x == reveredNumber || x == reveredNumber / 10){
//判断是否为素数
b = isPrime(n);
}
if(b){
return n;
}
}while(n++);
return n;
}
剑指 Offer 49. 丑数
丑数的定义就是只包含质因子2, 3, 5的正整数,并且认为1也是丑数。
要重点注意质因子,没有理解这个概念的话会有点蒙。
这道题我用动态规划思思维来讲解。
分析:
- 我们设dp[ i ] 表示第 i 个丑数,那么初始条件便是dp[ 1 ] = 1。
- 每个丑数都是由前一个丑数 * 2,*3或 *5得到,所以我们可以定义三个指针p2,p3,p5,分别指向 * 2,*3, *5的三个数。
以此类推。
代码如下:
int nthUglyNumber(int n){
int dp[n + 1];
dp[1] = 1;
int p2 = 1, p3 = 1, p5 = 1;
for(int i = 2; i <= n; i++){
int nums2 = dp[p2] * 2;
int nums3 = dp[p3] * 3;
int nums5 = dp[p5] * 5;
dp[i] = fmin(fmin(nums2, nums3), nums5);
if(nums2 == dp[i]){
p2++;
}
if(nums3 == dp[i]){
p3++;
}
if(nums5 == dp[i]){
p5++;
}
}
return dp[n];
}