问题描述
给你一个整数 n ,返回大于或等于 n 的最小回文质数。
一个整数如果恰好有两个除数:1 和它本身,那么它是 质数 。注意,1 不是质数。
例如,2、3、5、7、11 和 13 都是质数。
一个整数如果从左向右读和从右向左读是相同的,那么它是 回文数 。
例如,101 和 12321 都是回文数。
测试用例保证答案总是存在,并且在 [2, 2 * 108] 范围内。
示例 1:
输入:n = 6
输出:7
示例 2:
输入:n = 8
输出:11
示例 3:
输入:n = 13
输出:101
问题分析:
假设有一个回文串 XXX,下一个回文串是什么?
每个 ddd 长度的回文串都有一个 回文根,回文根为前 k=(d+1)/2
个数字。下一个回文串一定是由下一个回文根组成的。
举个例子,如果 123 是 12321 的回文根,那么下一个回文串 12421 的回文根就是 124。
需要注意一个回文根可能对应两个回文串,例如 123321,12321的回文根就都是 123。
解决方案:
算法
对于每个 回文根,找对应的两个回文串(一个奇数长度,一个偶数长度)。对于 k长度的回文根,会产生长度为 2∗k−1和 2∗k−1的回文串。
当检查回文串的时候,需要先检查小的 2k−1长度的,这里直接把数字变成字符串来检查是否对称。
至于检查素数,这里用的是常见的 O(根号N) 复杂度的算法来检查是不是素数,即检查小于(根号N)的数中有没有能整除 N 的。
上述求解方法来源于leetcode,更多求解方法: 点我
代码如下:
class Solution {
public int primePalindrome(int n) {
for(int i = 1;i <= 5;i++){
//从10开始,检查奇数长度回文串
for(int root = (int)Math.pow(10,i - 1);root < (int)Math.pow(10,i);root++){
StringBuilder sb = new StringBuilder(Integer.toString(root));
for(int k = i - 2;k >= 0;k--){
String s = sb.toString();
sb.append(s.charAt(k));
}
int x = Integer.valueOf(sb.toString());
if(x >= n && isPrime(x)){
return x;
}
}
//从1开始,检查偶数长度回文串
for(int root = (int)Math.pow(10,i - 1);root < (int)Math.pow(10,i);root++){
StringBuilder sb = new StringBuilder(Integer.toString(root));
for(int k = i - 1;k >= 0;k--){
String s = sb.toString();
sb.append(s.charAt(k));
}
int x = Integer.valueOf(sb.toString());
if(x >= n && isPrime(x)){
return x;
}
}
}
return -1;
}
//检查其是否为质数
public boolean isPrime(int x){
if(x < 2) return false;
int e = (int)Math.sqrt(x);
for(int i = 2;i <= e;i++){
if(x % i == 0) return false;
}
return true;
}
}