LeetCode : 866. 回文素数(Prime Palindrome)分析和解答

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/afei__/article/details/83721831

866. 回文素数

求出大于或等于 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

解答

思路:

判断素数的方法和判断回文数的方法都不难,难点在于怎么在短时间内完成,即不能超时。

起先我只是想办法优化寻找素数的方法,然后再去判断是否是回文数。然后发现一直会超时,原因是数字很大后,这样执行的效率很低。这题主要的优化策略在判断回文数上了,而素数的优化起到的是辅助性的增强。

数学规律1:除 11 外的偶数位回文数,都能被 11 整除

能被 11 整数的数字有个特点:它们的偶数位的和,等于他们奇数位的和。这是一条已经被证明的定理了,想要详细了解的话可以另行百度。

而偶数位的回文数,由于回文数的特点,以及它又是偶数位,所以它偶数位的和一定等于奇数位的和,即它能被 11 整除,所以除了 11 其余的都不是素数。

结论: 我们可以跳过所有位数为偶数的数字,除了 11。例如当输入 123456 时,我们可以直接从 1000001 开始查找。

数学规律2:除 2 和 3 外,所有的素数一定在 6 的两侧

什么意思呢,也就是说除了 2 和 3,其余素数一定等于 6x-16x +1,其中 x >= 1。

首先 6x 肯定不是质数,因为它能被 6 整除;其次 6x+2 肯定也不是质数,因为它还能被 2 整除;依次类推,6x+3 肯定能被 3 整除;6x+4 肯定能被 2 整除;6x+5 就等同于 6x-1

结论: 我们可以将遍历数字时的步长再增大点,而不是只过滤偶数。其次,在判断数字是否为素数时,我们也只需要判断该数字能否被 6 两侧的数字整除即可。(不少解法只过滤偶数,这样以 6 个数为单位,需要判断剩下的 3 个,而该方法只需要判断剩下的 2 个,效率提升 30% 左右)

注意: 你也可以选择只过滤偶数,同样可以在指定时间内完成。虽然会慢些,但是代码逻辑会简单不少。

其余优化

  1. 先使用上述两条数学规律过滤掉大量情况,这样我们需要实际计算的数字就少很多很多了。
  2. 其次对于满足上述两种条件的数字,我们先判断它是否是回文数,因为判断是回文数的效率会比判断是素数的效率高很多。
  3. 由于 11 是个特别的情况(同理还有 2 和 3),我不想在每次位数为偶数时还去判断它是不是 11,所以我选择直接把 11 以下的数单独处理了,它们也不多。

实现

代码中又多加了一些注释,应该不难理解了。

/**
 * Copyright © 2018 by afei. All rights reserved.
 * 
 * @author: afei
 * @date: 2018年11月3日
 */

class Solution {

    public static void main(String[] args) {
        // 这个例子很容易超时,要保证在一秒内完成,本例方法只需 10ms
        System.out.println(primePalindrome(9989900));
    }

    public static int primePalindrome(int N) {
        if (N <= 11) { // 单独处理 11 以下的数,包括 11
            if (N <= 2)
                return 2;
            else if (N == 3)
                return 3;
            else if (N <= 5)
                return 5;
            else if (N <= 7)
                return 7;
            else
                return 11;
        }
        // when N > 11
        int modulus = N % 6; // 这个用来挑选余数为 1 或 5 的数字
        switch (modulus) {
        case 0:
            N++;
        case 1:
            modulus = 1;
            break;
        case 2:
            N++;
        case 3:
            N++;
        case 4:
            N++;
        case 5:
            modulus = 5;
            break;
        }
        int[] nums = new int[10]; // 这个用来判断回文数的,长度 10 就够用了
        for (;;) {
            int length = getNumLength(N, nums);
            if ((length & 1) == 0) {
                // if length is even, palindrome must be divided by 11
                N = (int) Math.pow(10, length) + 1;
                modulus = 5; // modulus must be 5
                continue; // 跳过所有位数为偶数的数字
            }
            // here modulus must be 1 or 5
            if (isPalindrome(length, nums) && isPrime(N)) {
                return N;
            }
            // 步长为 2 或者 4,效率更高
            if (modulus == 1) {
                N += 4;
                modulus = 5;
            } else { // modulus == 5
                N += 2;
                modulus = 1;
            }
        }
    }

    public static int getNumLength(int N, int[] nums) {
        int length = 0;
        while (N > 0) {
            nums[length++] = N % 10;
            N /= 10;
        }
        return length;
    }

    public static boolean isPrime(int num) {
        int sqrt = (int) Math.sqrt(num);
        // We have filtered nums what "N % 6 != 1 || N % 6 != 5"
        for (int i = 5; i <= sqrt; i += 6) {
            // So here just check "i % 6 == 1 || i % 6 == 5" 
            if (num % i == 0 || num % (i + 2) == 0) {
                return false;
            }
        }
        return true;
    }

    public static boolean isPalindrome(int length, int[] nums) {
        for (int i = 0; i < length / 2; i++) {
            if (nums[i] != nums[length - i - 1]) {
                return false;
            }
        }
        return true;
    }
}

项目地址

https://github.com/afei-cn/LeetCode/tree/master/866.%20Prime%20Palindrome

原题地址

https://leetcode-cn.com/problems/prime-palindrome/description/

猜你喜欢

转载自blog.csdn.net/afei__/article/details/83721831