判断质数(素数)

  • 我们知道质数的定义就是 除了1和他本身,没有其他的因数,于是根据定义
    很容易写出这样的代码
static boolean isPrime1(int num) {
		if(num<=1) return false;
		if(num<=3) return true;
		for(int i =2;i<num;i++) {
			if(num%i==0) return false;
		}
		return true;
	}
  • 不难想到,如果是2或者3 的倍数,那一定不是质数,所以进行进一步优化:
static boolean isPrime2(int num) {
		if(num<=1) return false;
		if(num<=3) return true;
		if(num%2 ==0||num%3 ==0) return false;
		for(int i =2;i<num;i++) {
			if(num%i==0) return false;
		}
		return true;
	}
  • 再想一想:一个数字可以被分解成两个数字相乘,举个例子:
    • 21 ->1 * 21

    •  3 * 7
      
    •  7 * 3
      
    •  21 * 1
      
    • 16 ->1 * 16

    •  2 * 8
      
    •  4 * 4
      
    •  8 * 2
      
    •  16 * 1
      
    • 你看到了什么? 是不是枚举的这些数字里总有一些重复枚举的,就像 3 * 7 和7 * 3 一样
      其实代码里的i 也就是这个情况,那怎么优化呢?其实只需要将num开方,

    • 比如:21开方是一个4点多的数字,此时就只需要枚举到4就够了,
      16开方是4,枚举到4也就够了,就能正好排除掉重复的组

    • 这个原理如果看着晕,实在不想看数学公式,可以保留,等熟悉掌握了再看也不迟。

    • 原理也很简单:就是x * y =z => y = z/x看成一个反比例函数,该反比例函数
      上有很多组整数数据, 我们的任务就是选出一个点,让这个点能均分反比例函数
      由于该反比例函数关于y=x对称,因此当x == y的时候,就是最中间的点,此时带入
      z = xy =>x = y = 根号z
      因此i<num的条件又能进一步优化成i<=Math.sqrt(num) 一定要带等号,就像是16那个例子一样,4
      4是最中间的一组,也是唯一的一组,

    • 这就是他的特殊之处,是奇数组数据,最中间的那一组数组正好停留在了中点

    • i<=Math.sqrt(num)也能替代为:
      i*i<=num
      i<=num/i (防止乘法溢出)

    • 优化结果:

static boolean isPrime3(int num) {
		if(num<=1) return false;
		if(num<=3) return true;
		if(num%2 ==0||num%3 ==0) return false;
		for(int i =2;i<=num/i;i++) {
			if(num%i==0) return false;
		}
		return true;
	}
  • 再进行优化:

    • 根据数学归纳法,验证,除了2,3,一个质数,一定是在6倍数的左边或右边,
      还是有就是在每个以6为间隔的数字中除了6倍数左右两旁的数字,其他数字要么是
      2的倍数要么是3的倍数,所以下面的条件可以是

      • 1,排除这个数是2或3的倍数,
        if(num%2 ==0 || num% 3 == 0) return false;

      • 2,如果这个数字不在6的倍数的旁边,那这个数一定不是质数
        if(!(num%6 == 1 ||num%6 == 5)) return false;
        将!号去掉,等价于if(num%6 != 1 && num%6 != 5) return false;

    • 无论是1,还是2 都是对的,他们只是思想不同,但结果是一样的,选一个用即可。


```java
static boolean isPrime4(int num) {
		if(num<=1) return false;
		if(num<=3) return true;
		
		if(num%2 ==0 || num% 3 == 0) return false;
		//if(!(num%6 == 1 ||num%6 == 5)) return false;
		//if(num%6 != 1 && num%6 != 5) return false;
		for(int i = 5;i<=num/i;i+=6) {
			/**
			 * 上面说过了只有是在6的倍数的旁边的数才可能算是质数,走到这一步说明这个数字一定在
			 * 6的倍数的旁边,此时这个数字虽然已经排除了是他数字的倍数,但是要
			 * 	判断这个数字是否是6的倍数的旁边的数字的倍数,就像是
			 * 6的旁边可以是5,24旁边有25,如果要判断25是不是质数,就要防止
			 * 他是否是质数5的倍数。
			 */
			if(num%i ==0 || num%(i+2) == 0)return false;
		}
		return true;
	}
  • 最终版,今后判断质数就能直接用下面的模版
static boolean isPrime(int num) {
		if(num<=1) return false;
		if(num<=3) return true;
		if(num%2 ==0 || num% 3 == 0) return false;
		for(int i = 5;i<=num/i;i+=6) {
			if(num%i ==0 || num%(i+2) == 0)return false;
		}
		return true;
	}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值