《算法零基础100讲》(第7讲) 素数判定(题解)

866. 回文素数

在这里插入图片描述
在这里插入图片描述
对于这道题,我们可以先将它拆分为两部分,回文和素数。
一. 首先我们先判断回文数,回文数的意思就是一个数的正向和反向的数字是一样的,例如:121,1221,12321等。

  1. 得到一个数的反向我们只需要通过 % 和 / 两个操作符,不断辗转,最后得到。
    在这里插入图片描述
  2. 但是这种将一个整数整个反转的方法有点费时,毕竟我们只需判断,不需要计算。通过分析我们很容易可以看出,每个回文数都有一个对称轴可以将其对半划分,并且两边时一样得,所以我们可以反转后半部分,再与前半部分对比,如果一致则返回true。
    在这里插入图片描述
  3. 但是我们还要考虑当位数为奇数的情况,按照上面的思路,如果时12321,循环结束后,我们会得到,reveredNumber = 123,n = 12,这种情况我们只需判断reveredNumber的前面两位数就行,所以我们的判断条件可以设为 if(reveredNumber == n || reveredNumber % 10 ==n)。

二.我们在考虑第二部分——素数
  素数的定义是只有1和其本身这两个数是他的因子的数为素数。
  判断一个数n是否为素数,我们只需在区间[2, n) 进行计算,如果在这个区间内还有其他的数可以整除n,则返回false。
  但这样的计算量会很大,有没有什么方法能够对其进行优化呢?答案是肯定的。
  我们不妨设x是n的一个因子,那么n / x 为一个整数,且 n / x也是n的一个因子,我们不妨设:

x ≤ n / x
两边同乘x,得:
x ^ 2 ≤ n
得:
x ≤ √n
那么我们只需遍历区间[2, √n]的范围。

代码如下:

bool isPrime(int n) {              
    int i, sqrtn = sqrt(n + 1e-6);
    if(n <= 1) {
        return false;                
    }
    for(i = 2; i <= sqrtn; ++i) {
        if(n % i == 0) {         
            return false;
        }
    }
    return true;                   
}

int primePalindrome(int n){
    do{
    	//大于八位的数没有素数,所以直接返回100030001
        if(n >= 10000000)return 100030001;
        int x = n;
        if(x % 10 == 0 && x != 0){
            continue;
        }
        int reveredNumber = 0;
        //判断是否为回文数
        while(x > reveredNumber){
            reveredNumber *= 10;
            reveredNumber += x % 10;
            x /= 10;
        }
        bool b = false;
        if(x == reveredNumber || x == reveredNumber / 10){
            //判断是否为素数
            b = isPrime(n);
        }
        if(b){
            return n;
        }
    }while(n++);
    return n;
}

剑指 Offer 49. 丑数

在这里插入图片描述
丑数的定义就是只包含质因子2, 3, 5的正整数,并且认为1也是丑数。
要重点注意质因子,没有理解这个概念的话会有点蒙。
这道题我用动态规划思思维来讲解。
分析:

  1. 我们设dp[ i ] 表示第 i 个丑数,那么初始条件便是dp[ 1 ] = 1。
  2. 每个丑数都是由前一个丑数 * 2,*3或 *5得到,所以我们可以定义三个指针p2,p3,p5,分别指向 * 2,*3, *5的三个数。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    以此类推。

代码如下:

int nthUglyNumber(int n){
    int dp[n + 1];
    dp[1] = 1;
    int p2 = 1, p3 = 1, p5 = 1;
    for(int i = 2; i <= n; i++){
        int nums2 = dp[p2] * 2;
        int nums3 = dp[p3] * 3;
        int nums5 = dp[p5] * 5;
        dp[i] = fmin(fmin(nums2, nums3), nums5);
        if(nums2 == dp[i]){
            p2++;
        }
        if(nums3 == dp[i]){
            p3++;
        }
        if(nums5 == dp[i]){
            p5++;
        }
    }
    return dp[n];
    
}
  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

友人苏

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值