素数判断算法

方法1:时间复杂度O(n)

  • 最直观的方法,根据定义,因为质数除了1和本身之外没有其他约数,所以判断n是否为质数,根据定义直接判断从2到n-1是否存在n的约数即可
function isPrime(num){
  if(num ==2 || num==3)
          return num;
  for (var i = 2;i <= n-1;i++) {
    if(num % i ==0){
      return false;
    }
  }
  return num;
}

方法2:时间复杂度O(logN)

  • 上述判断方法,明显存在效率极低的问题。对于每个数n,其实并不需要从2判断到n-1
  • 我们知道,一个数若可以进行因数分解,那么分解时得到的两个数,一定是一个小于等于sqrt(n)和一个大于等于sqrt(n)
  • 据此,上述代码中并不需要遍历到n-1,遍历到sqrt(n)即可,因为若sqrt(n)左侧找不到约数,那么右侧也一定找不到约数
    12
    1×12=12
    2×6=12
    3×4=12
    4×3=12
  • 能被2整除的数一定不是素数,所以不用被4、6整除,这样能减少n/2次执行次数
  • 能被3整除的数一定不是素数,所以不用被6、9整除,这样能继续减少执行次数
function isPrime(num){      
  if(num ==2|| num==3 )
    return num;
  var temp = parseInt(Math.sqrt(num));
  for (var i = 2;i <= temp;i++) {
    if(num % i ==0){
      return false;
    }
  }
  return num;
  }

方法3:时间复杂度O(logN/2)

  • 2x,3x,5x肯定不是质数
  • 此时判断质数可以2个为单元快进,即在循环中i++步长加大为2,加快判断速度
function isPrime(num){
  if(num ==2 || num==3)
        return num;
  if(num % 2 == 0 || num % 3 == 0 || num % 5 == 0)
    return false;       
  var temp = parseInt(Math.sqrt(num));
  for (var i = 7;i <= temp;i=i+2) {
    if(num % i == 0){
      return false;
    }
  }
  return num;
}   

方法4:时间复杂度O(logN/6)

  • 证明:令x≥1,将大于等于5的自然数表示如下:
  • ······ 6x-1,6x,6x+1,6x+2,6x+3,6x+4,6x+5,6(x+1),6(x+1)+1 ······
  • 可以看到,6的倍数两侧之外的数为6x+2,6x+3,6x+4,由于2(3x+1),3(2x+1),2(3x+2),所以它们一定不是素数,再加上6x本身也不是素数
    • 所以在6的倍数两侧的一定是质数,及:if(num %6!= 1&&num %6!= 5) return false ;
    • 在6的倍数相邻两侧并不是一定就是质数
  • 此时判断质数可以6个为单元快进,即在循环中i++步长加大为6,加快判断速度
    • 原因是,假如要判定的数为n,则n必定是6x-1或6x+1的形式,对于循环中6i-1,6i,6i+1,6i+2,6i+3,6i+4,其中如果n能被6i,6i+2,6i+4整除,则n至少得是一个偶数,但是6x-1或6x+1的形式明显是一个奇数,故不成立
    • 另外,如果n能被6i+3整除,则n至少能被3整除,但是6x能被3整除,故6x-1或6x+1(即n)不可能被3整除,故不成立。
    • 综上,循环中只需要考虑6i-1和6i+1的情况,即循环的步长可以定为6,每次判断循环变量k和k+2的情况即可,理论上讲整体速度应该会是方法(2)的3倍
function isPrime(num){
  //两个较小数
  if(num == 2 || num == 3 )
    return num ;
  //不在数字6(6的倍数)的两侧一定不是质数,在数字6的两侧可能是素数
  //5 6 7,11 12 13,17 18 19,23 24 25
  if(num%6 != 1 && num%6 != 5){
    return false ;
  }    
  var tmp =Math.sqrt(num);
  //在6的倍数两侧的也可能不是质数
  for(var i = 5;i <= tmp; i+=6 )
    //判断6左边和6右边,及5和7的倍数
    if(num%i == 0 || num%(i+2) == 0)
      return false ;                 
  return num;
}
posted @ 2020-09-15 16:42  MrFlySand-飞沙  阅读(370)  评论(0编辑  收藏  举报