【OD机试题笔记】生成回文素数

题目描述

求出大于或等于 N 的最小回文素数。

如果一个数大于 1,且其因数只有 1 和它自身,那么这个数是素数。 例如,2,3,5,7,11 以及 13 是素数。

如果一个数从左往右读与从右往左读是一样的,那么这个数是回文数,例如,12321 是回文数。

输入描述
一个数

输出描述
一个数

**示例1
输入
6
输出
7
说明

**示例2
输入
8
输出
11

思路

  1. 枚举:从N开始逐个遍历整数,保证找“最小”;
  2. 双校验
    • 回文数:字符串反转后与原串对比或用双指针判断;
    • 素数:基于定理(仅验到√n,跳过偶数)判定;
  3. 终止:找到首个同时满足的数即输出。

核心优化

  • 素数校验:范围缩至√n,仅验奇数;
  • 枚举:跳过大于2的偶数,减少无效遍历。

代码

function solution() {
    // 读取输入的数字N,目标是找到≥N的最小回文素数
    const N = Number(readline());

    /**
     * 判断一个数是否是回文数
     * 回文数定义:从左到右读和从右到左读完全一致的数
     * @param {number} n - 待判断的数字
     * @returns {boolean} 是回文数返回true,否则返回false
     */
    function isPalindrome(n) {
        const s = n.toString(); // 转为字符串便于反转对比
        // 反转字符串:split拆分为数组→reverse反转→join还原为字符串,与原字符串对比
        return s === s.split('').reverse().join('');
    }

    /**
     * 判断一个数是否是素数(核心逻辑,含素数定理和多重优化)
     * 素数定义:大于1,且只能被1和自身整除的自然数
     * 素数判断核心定理:
     * 1. 若数n有大于√n的因数,则必然存在一个对应的小于√n的因数,因此只需校验到√n即可
     * 2. 除2外,所有偶数都不是素数;除3外,所有3的倍数都不是素数(此处仅优化偶数)
     * @param {number} n - 待判断的数字
     * @returns {boolean} 是素数返回true,否则返回false
     */
    function isPrime(n) {
        // 边界1:≤1的数不是素数
        if (n <= 1) return false;
        // 边界2:2是唯一的偶素数,直接返回true
        if (n === 2) return true;
        // 优化1:大于2的偶数必然不是素数,直接排除(减少50%的校验量)
        if (n % 2 === 0) return false;

        // 优化2:仅校验奇数,且只需校验到√n(用i*i ≤n替代Math.sqrt(n),避免浮点精度误差)
        // 起始值为3(已排除偶数),步长为2(只遍历奇数)
        for (let i = 3; i * i <= n; i += 2) {
            // 若能被整除,说明存在1和自身外的因数,不是素数
            if (n % i === 0) {
                return false;
            }
        }
        // 所有校验通过,是素数
        return true;
    }

    // 从N开始枚举,寻找第一个满足“回文数+素数”的数
    let num = N;
    while (true) {
        // 同时满足回文数和素数,即为目标值,输出并终止程序
        if (isPalindrome(num) && isPrime(num)) {
            console.log(num);
            return;
        }
        num++; // 不满足则枚举下一个数
        // 额外优化:跳过大于2的偶数(减少无效枚举,与isPrime中的偶数判断形成双重优化)
        if (num > 2 && num % 2 === 0) {
            num++;
        }
    }
}


// 测试用例
const cases = [
    `6`,
    `8`
];

let caseIndex = 0, lineIndex = 0;
const readline = (() => {
    let lines = [];
    return () => {
        if (!lineIndex) lines = cases[caseIndex].trim().split('\n').map(l => l.trim());
        return lines[lineIndex++];
    };
})();

cases.forEach((_, i) => {
    caseIndex = i;
    lineIndex = 0;
    solution();
    console.log('-------');
});

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值