最近几天电脑拿去修,系统还被重装了,今天才写了一个,回文素数,真是折腾的我够呛,不过好在还是出来了。
题目
求出大于或等于 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
。
分析
两个要求:一得是回文数字,二要是素数。
判断回文和判断素数都很简单啊,回文用字符串反转一下然后equals方法,判断素数从c语言就开始学,于是,我成功的timelimited。
超出时间了,是判断素数的方法不够高效?换了一种网上高效的方法,比较了一下两者的时间,都是八秒多,并没有很大的差别啊,那就只能是判断回文喽,于是把判断素数的一块注释掉,看了一下判断回文,八秒,原来时间都在这上面超了。
一开始写的是从N开始向后依次+1遍历每一个数字,判断是否是回文,其实并不用每个数字都判断,偶数就不用判断,肯定不是素数啊,于是把+1 变成了+2,这样就少遍历一半的数字,时间也减少了一半,但还是超时的。处理字符串太耗费时间,那就把数字处理一下用数组来保存,题目中给出了数字限制小于 2 * 10^8 ,也就是小于9位,那么把数组开到10位大小,再用一个len变量记录长度。时间一下子缩小到了一两秒钟。
看网上说偶数位的回文(除去11)都不是素数,理由如下:
11的整倍数有一个性质,那就是奇数位上数字之和=偶数位上数字之和.
一个数,如果是偶数长度回文数,那么同一个数x,必然出现在一次奇数位一次偶数位,所以这个偶数长度回文数可以被11整除.
那么可以通过上面定义的len来判断是该数字是偶数位还是奇数位,如果是偶数位,则直接跳过之后所有的偶数位的数字的判断,跳到它之后的最小的奇数位的数字(当然还要是一个奇数)。这样一来,时间上就缩短更多了。
对于判断素数上面,在网上也看了不少,但对于这道题来说,时间上面差出去的并不是很多,所以就用了最简单的判断素数的方法。
代码
class Solution {
public int primePalindrome(int N) {
if (N <= 2) return 2;
N = N%2==0 ? N+1 : N;//将N处理为奇数
for (int i = N; ; ) {
int k = i;
int len = 0;//判断数字的位数
int[] nums = new int[10];
while(k / 10 != 0){//将判断的数字处理放入数组中
nums[len++] = k % 10;
k /= 10;
}
nums[len++] = k;
if ( len%2 == 0 && i != 11) //判断是否是除11之外的偶数位数字
i = (int)Math.pow(10,len)+1;//直接跳过偶数位数字
else {
if (isHui(i,nums,len)) //是否是回文 即判断一下数组中的数字是否对称
if (isprime(i)) return i;//是否是素数
i+=2;
}
}
}
public static boolean isprime(int i){
for (int j = 2; j <= Math.sqrt(i); j++)
if (i % j == 0) return false;
return true;
}
public static boolean isHui(int i, int[] nums, int len){
for (int j = 0; j < len/2; j++)
if (nums[j] != nums[len-j-1]) return false;
return true;
}
}