版权声明:本文为博主原创文章,博客地址:https://blog.csdn.net/qq_41855420,未经博主允许不得转载。 https://blog.csdn.net/qq_41855420/article/details/91351016
求出大于或等于 N 的最小回文素数。
回顾一下,如果一个数大于 1,且其因数只有 1 和它自身,那么这个数是素数。
例如,2,3,5,7,11 以及 13 是素数。
回顾一下,如果一个数从左往右读与从右往左读是一样的,那么这个数是回文数。
例如,12321 是回文数。
示例 1:
输入:6
输出:7
示例 2:
输入:8
输出:11
示例 3:
输入:13
输出:101
提示:
1 <= N <= 10^8
答案肯定存在,且小于 2 * 10^8。
这道题可能有一部分的人上来就开始暴搜,然而测试数据量不大,蛋式数据非常大。这道题有几个需要注意点:
第一点:我们不能直接去穷举num,然后判断这个数是否素数、回文数,我们可以先从小到大构造回文数,然后去判断它是否是素数。(有人可能会问,能不能直接构造素数,再判断是否是回文数?这种思路理论上是可行的,蛋式从小到大构造素数会比从小到大构造回文数要难一些。)
第二点:对于偶数长度的回文数,都能被“11”整除。因此大于“11”的偶数长度的 回文数 只有“11”是质数。所以如果遇到“1001”这种,可以直接跳到“10001”开始,因为[1001, 9999]中的回文数都能被“11”整除。(这是一个数学定律,可以自行百度)
第三点:有第二点可知,我们构造的回文数都是奇数长度,比如“12321”,回文特性为关于中间数字对称,比如其中的"12"和“21”关于中间的’3’对称。那么回文构造的下一个数是什么?如果你此时想着直接把“12321” + 1,然后接着构造,那么这会消耗大量的时间。我们需要直接构造出下一个回文数“12421”,不难发现,增量tempVal = “100” = pow(10, len(“12421”) / 2)。
具体实现:
class Solution {
public:
int primePalindrome(int N) {
if (N < 12){
//对于小于12的,可直接找出对应的结果
for (int i = N; i < 100; ++i){
if (isPrime(i)){
return i;
}
}
}
int tempVal = 1;//构造回文的增量
for (int i = N; i < INT_MAX / 10; i += tempVal){
string nStr = to_string(i);
int strSize = nStr.size();//数字的长度
//数字长度为偶数的回文数字都能被11整除,也就是说比如"1001",在“1001 - 9999”这些偶数长度的回文数字中没有质数
if (strSize % 2 == 0){
i = pow(10, strSize);//比如“1001”,直接跳到“10000”,也就是数字长度增大一位
nStr = to_string(i);
}
tempVal = pow(10, strSize / 2);//重新计算增量,比如“12321”的下一个元素为“12421”,增量为“100”
string rightStr = nStr.substr(0, strSize / 2);
reverse(rightStr.begin(), rightStr.end());//将左半边对称反转为右半边
//然后将left + 中间数字 + right合并
i = stoi(nStr.substr(0, strSize / 2 + 1) + rightStr);
if (i < N){
continue;
}
//由于构造的i已经是回文,所以只要判断它是否是质数,并且比N大
if (isPrime(i)){
return i;
}
}
return -1;
}
//判断num是否是质数
bool isPrime(int num){
if (num == 1){
return false;
}
//查找[1, sqrt(num)]是否有因子
for (int i = sqrt(num); i > 1; --i){
if (num % i == 0){
return false;
}
}
return true;
}
};