Leetcode 866:回文素数

题目描述:

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

猜你喜欢

转载自blog.csdn.net/weixin_47382783/article/details/119510142
今日推荐