题目描述:
求出大于或等于 N 的最小回文素数。
回顾一下,如果一个数大于 1,且其因数只有 1 和它自身,那么这个数是素数。例如,2,3,5,7,11 以及 13 是素数。
回顾一下,如果一个数从左往右读与从右往左读是一样的,那么这个数是回文数。例如,12321 是回文数。
示例 1:
输入:6
输出:7
示例 2:
输入:8
输出:11
示例 3:
输入:13
输出:101
解题思路:
这道题并不难理解,思路也很明确:分别找到素数和回文数即可。因此,大多数人的想法是通过暴力破解法来实现,很不巧,超出时间限制了。因此,就需要进行优化。首先,是对查找顺序的优化:先找回文数,再找素数。这样做就减少了判断的次数。举个例子:100以内的素数有25个,而100以内的回文数只有18个。接下来就是对回文数的优化,这里的思路是:根据N制造出一个回文数,就是将N的前半段进行翻转,例如:1234取前半段12翻转得到1221,4628取前半段46翻转得到4664。如果翻转之后的数字小于N,就像前面的1221,那就把N的前半段+1,再次翻转,再制造回文数,1234就变成1331。
代码:
class Solution {
public int primePalindrome(int N) {
while (true) {
N = getNextPalindrome(N); // 获取>=N的回文数
if(isPrime(N)) return N; // 判断是不是素数
N++;
}
}
// 获取下一个>=n的回文数
private int getNextPalindrome(int n) {
char[] s = String.valueOf(n).toCharArray();
int mid = s.length/2;
while (true) {
// 制造回文数:把前半段翻转一下复制到后半段
for (int i = 0; i < mid; i++) {
s[s.length -1 - i] = s[i];
}
// 判断制造出来的数是否>=n
int tmp = Integer.valueOf(String.valueOf(s));
if (tmp >= n) return tmp; // 如果>=n,返回这个造出来的数
// 如果比n小,那前半段+1
else {
int j = s.length % 2 == 1? mid: mid-1; // 如果是奇数长度,最靠近中轴的是s[mid];如果是偶数长度,最靠近中轴的是s[mid-1]
// 有9要进位(不用考虑999xxx这样首位要进位的,因为999999这个回文数肯定>=所有999xxx形式的n)
while (s[j] == '9'){
s[j--] = '0';
}
s[j]++;
}
}
}
// 判断是否是素数
private boolean isPrime(int num){
// 一般从2找到n/2,判断是否能被整除。从5开始,n/2>√n,这样可以减少运算量。
if(num <= 5) {
return num == 2 || num == 3 || num == 5;
}
// 从2找到√num
for (int i = 2; i <= Math.sqrt(num); i++) {
if(num % i == 0) return false;
}
return true;
}
}