编写方法求求反素数
反素数(Emirp)是素数中一个有趣的变种,它本身是素数,反转后的数字也是素数,并且不能是回文数。
反素数基础实现
编写一个程序,要求编写方法public static boolean isPrime(int num)
判断是否为素数;编写方法public static int reversal(int number)
实现数字倒置;编写方法public static boolean isEmirp(int num)
判断是否为反素数;编写方法public static void showEmirps(int count)
显示前N个反素数。
java
# 源文件保存为"EmirpNumbers.java"
public class EmirpNumbers {
// 判断是否为素数
public static boolean isPrime(int num) {
if (num <= 1) return false;
if (num == 2) return true;
if (num % 2 == 0) return false;
for (int i = 3; i * i <= num; i += 2) {
if (num % i == 0) return false;
}
return true;
}
// 数字倒置
public static int reversal(int number) {
int reversed = 0;
while (number != 0) {
reversed = reversed * 10 + number % 10;
number /= 10;
}
return reversed;
}
// 判断是否为反素数
public static boolean isEmirp(int num) {
int reversed = reversal(num);
return num != reversed && isPrime(num) && isPrime(reversed);
}
// 显示前N个反素数
public static void showEmirps(int count) {
int found = 0, num = 2;
while (found < count) {
if (isEmirp(num)) {
System.out.printf("%6d", num);
if (++found % 10 == 0) System.out.println();
}
num++;
}
}
public static void main(String[] args) {
System.out.println("前30个反素数:");
showEmirps(30);
}
}
运行结果
makefile
前30个反素数:
13 17 31 37 71 73 79 97 107 113
149 157 167 179 199 311 337 347 359 389
701 709 733 739 743 751 761 769 907 937
代码解析:
isPrime
方法通过试除法判断素数,优化了偶数检查reversal
方法通过模运算和整数除法实现数字倒置isEmirp
方法组合前两个方法,并排除回文数情况showEmirps
方法从2开始逐个检查,直到找到足够数量的反素数
变体案例解析
双反素数
编写一个程序,要求编写方法public static boolean isPrime(int num)
判断是否为素数;编写方法public static int reversal(int number)
实现数字倒置;编写方法public static boolean isEmirp(int num)
判断是否为反素数;编写方法public static void showDoubleEmirps(int count)
寻找反转前后都是反素数的特殊数。
java
# 源文件保存为"EmirpNumbers.java"
public class EmirpNumbers {
// 判断是否为素数
public static boolean isPrime(int num) {
if (num <= 1) return false;
if (num == 2) return true;
if (num % 2 == 0) return false;
for (int i = 3; i * i <= num; i += 2) {
if (num % i == 0) return false;
}
return true;
}
// 数字倒置
public static int reversal(int number) {
int reversed = 0;
while (number != 0) {
reversed = reversed * 10 + number % 10;
number /= 10;
}
return reversed;
}
// 判断是否为反素数
public static boolean isEmirp(int num) {
int reversed = reversal(num);
return num != reversed && isPrime(num) && isPrime(reversed);
}
// 显示前N个双反素数
public static void showDoubleEmirps(int count) {
int found = 0, num = 2;
while (found < count) {
if (isEmirp(num)) {
int reversed = reversal(num);
if (isEmirp(reversed)) {
System.out.printf("(%d, %d) ", num, reversed);
if (++found % 3 == 0) System.out.println();
}
}
num++;
}
}
public static void main(String[] args) {
System.out.println("前30个双反素数:");
showDoubleEmirps(30);
}
}
运行结果
makefile
前30个双反素数:
(13, 31) (17, 71) (31, 13)
(37, 73) (71, 17) (73, 37)
(79, 97) (97, 79) (107, 701)
(113, 311) (149, 941) (157, 751)
(167, 761) (179, 971) (199, 991)
(311, 113) (337, 733) (347, 743)
(359, 953) (389, 983) (701, 107)
(709, 907) (733, 337) (739, 937)
(743, 347) (751, 157) (761, 167)
(769, 967) (907, 709) (937, 739)
发现:这个方法会找到像(13, 31)、(17, 71)这样的数字对。这类数字在密码学中有特殊意义,因为正反都可以作为密钥。
指定范围内的反素数
编写一个程序,要求编写方法public static boolean isPrime(int num)
判断是否为素数;编写方法public static int reversal(int number)
实现数字倒置;编写方法public static boolean isEmirp(int num)
判断是否为反素数;编写方法public static void showEmirpsInRange(int start, int end)
查找某个区间内的所有反素数。
java
# 源文件保存为"EmirpNumbers.java"
public class EmirpNumbers {
// 判断是否为素数
public static boolean isPrime(int num) {
if (num <= 1) return false;
if (num == 2) return true;
if (num % 2 == 0) return false;
for (int i = 3; i * i <= num; i += 2) {
if (num % i == 0) return false;
}
return true;
}
// 数字倒置
public static int reversal(int number) {
int reversed = 0;
while (number != 0) {
reversed = reversed * 10 + number % 10;
number /= 10;
}
return reversed;
}
// 判断是否为反素数
public static boolean isEmirp(int num) {
int reversed = reversal(num);
return num != reversed && isPrime(num) && isPrime(reversed);
}
public static void showEmirpsInRange(int start, int end) {
int count = 0;
for (int num = start; num <= end; num++) {
if (isEmirp(num)) {
System.out.printf("%6d", num);
if (++count % 10 == 0) System.out.println();
}
}
System.out.println("\n在" + start + "到" + end + "区间共找到" + count + "个反素数");
}
public static void main(String[] args) {
System.out.print("反素数:");
showEmirpsInRange(0, 30);
}
}
实用技巧:当处理大范围时,可以预先筛选素数再判断反素数属性,提高效率。这种方法在数据分析时特别有用,比如统计千万级数字中反素数的分布规律。
反素数链
编写一个程序,要求编写方法public static boolean isPrime(int num)
判断是否为素数;编写方法public static int reversal(int number)
实现数字倒置;编写方法public static boolean isEmirp(int num)
判断是否为反素数;编写方法public static void findEmirpChain(int length)
查找找能形成多级反转仍为素数的数字链。
java
# 源文件保存为"EmirpNumbers.java"
public class EmirpNumbers {
// 判断是否为素数
public static boolean isPrime(int num) {
if (num <= 1) return false;
if (num == 2) return true;
if (num % 2 == 0) return false;
for (int i = 3; i * i <= num; i += 2) {
if (num % i == 0) return false;
}
return true;
}
// 数字倒置
public static int reversal(int number) {
int reversed = 0;
while (number != 0) {
reversed = reversed * 10 + number % 10;
number /= 10;
}
return reversed;
}
// 判断是否为反素数
public static boolean isEmirp(int num) {
int reversed = reversal(num);
return num != reversed && isPrime(num) && isPrime(reversed);
}
public static void findEmirpChain(int length) {
int num = 2;
while (true) {
int current = num;
boolean isChain = true;
System.out.print("测试 " + num + ": ");
for (int i = 0; i < length; i++) {
System.out.print(current + " ");
if (!isPrime(current)) {
isChain = false;
break;
}
current = reversal(current);
if (current == reversal(current)) { // 排除回文
isChain = false;
break;
}
}
if (isChain) {
System.out.println(" ← 发现长度为" + length + "的反素数链");
break;
}
System.out.println();
num++;
}
}
public static void main(String[] args) {
findEmirpChain(3);
}
}
运行结果
yaml
测试 2: 2
测试 3: 3
测试 4: 4
测试 5: 5
测试 6: 6
测试 7: 7
测试 8: 8
测试 9: 9
测试 10: 10
测试 11: 11
测试 12: 12
测试 13: 13 31 13 ← 发现长度为3的反素数链
有趣现象:当length设为3时,能找到像13→31→13这样的循环链。这类数字在数学游戏和谜题中很受欢迎。
实战练习题
基础题
优化素数判断 :修改isPrime
方法,使用6k±1优化法(所有大于3的素数都可以表示为6k±1的形式),减少不必要的检查。
java
# 源文件保存为"EmirpNumbers.java"
public class EmirpNumbers {
// 判断是否为素数
public static boolean isPrime(int num) {
if (num <= 3) return num > 1;
if (num % 2 == 0 || num % 3 == 0) return false;
for (int i = 5; i * i <= num; i += 6) {
if (num % i == 0 || num % (i + 2) == 0) {
return false;
}
}
return true;
}
// 数字倒置
public static int reversal(int number) {
int reversed = 0;
while (number != 0) {
reversed = reversed * 10 + number % 10;
number /= 10;
}
return reversed;
}
// 判断是否为反素数
public static boolean isEmirp(int num) {
int reversed = reversal(num);
return num != reversed && isPrime(num) && isPrime(reversed);
}
// 显示前N个反素数
public static void showEmirps(int count) {
int found = 0, num = 2;
while (found < count) {
if (isEmirp(num)) {
System.out.printf("%6d", num);
if (++found % 10 == 0) System.out.println();
}
num++;
}
}
public static void main(String[] args) {
System.out.println("前30个反素数:");
showEmirps(30);
}
}
提高题
反素数间距分析:编写方法分析反素数之间的间隔规律,找出最大间隔和平均间隔。
java
# 源文件保存为"EmirpNumbers.java"
public class EmirpNumbers {
// 判断是否为素数
public static boolean isPrime(int num) {
if (num <= 1) return false;
if (num == 2) return true;
if (num % 2 == 0) return false;
for (int i = 3; i * i <= num; i += 2) {
if (num % i == 0) return false;
}
return true;
}
// 数字倒置
public static int reversal(int number) {
int reversed = 0;
while (number != 0) {
reversed = reversed * 10 + number % 10;
number /= 10;
}
return reversed;
}
// 判断是否为反素数
public static boolean isEmirp(int num) {
int reversed = reversal(num);
return num != reversed && isPrime(num) && isPrime(reversed);
}
public static void analyzeEmirpGaps(int count) {
int prev = 2, maxGap = 0, sumGaps = 0;
int found = 0, num = 2;
while (found < count) {
if (isEmirp(num)) {
int gap = num - prev;
if (gap > maxGap) maxGap = gap;
sumGaps += gap;
prev = num;
found++;
}
num++;
}
System.out.println("前"+count+"个反素数分析:");
System.out.println("最大间隔: "+maxGap);
System.out.println("平均间隔: "+(double)sumGaps/count);
}
public static void main(String[] args) {
analyzeEmirpGaps(30);
}
}
运行结果
makefile
前30个反素数分析:
最大间隔: 312
平均间隔: 31.166666666666668
深入理解
反素数问题看似简单,却融合了数论、算法优化和编程技巧。素数判断的优化方法在实际密码学应用中至关重要,RSA加密算法就依赖大素数的快速判断。数字反转算法在处理身份证校验、信用卡号验证等场景也有广泛应用。
调试这类数字处理程序时,边界条件需要特别注意。比如数字0的反转、整型溢出(反转后的数字可能超过Integer.MAX_VALUE)、负数处理等。良好的做法是添加参数校验和异常处理:
性能方面,当需要查找大量反素数时,可以考虑使用埃拉托斯特尼筛法预先生成素数表,然后在这个表中查询反转数。这种方法用空间换时间,特别适合需要反复查询的场景。