【问题标题】:Check if number is prime in O(sqrt(n)) in Scala检查数字是否在 Scala 中的 O(sqrt(n)) 中为素数
【发布时间】:2017-09-03 17:31:36
【问题描述】:

在 Scala 中检查 n 是否为素数时,最常见的解决方案是简洁的单行,几乎可以在所有类似的 SO 问题中看到

  def isPrime1(n: Int) = (n > 1) && ((2 until n) forall (n % _ != 0))

继续,重写它以仅检查奇数很简单

  def isPrime2(n: Int): Boolean = {
    if (n < 2) return false
    if (n == 2) return true
    if (n % 2 == 0) false
    else (3 until n by 2) forall (n % _ != 0)
  }

但是,为了提高效率,我想将仅检查赔率与计数到 sqrt(n) 结合起来,但不使用 Math.sqrt。所以,作为i &lt; sqrt(n) &lt;==&gt; i * i &lt; n,我会编写类似C的循环:

def isPrime3(n: Int): Boolean = {
    if (n < 2) return false
    if (n == 2) return true
    if (n % 2 == 0) return false
    var i = 3
    while (i * i <= n) {
      if (n % i == 0) return false
      i += 2
    }
    true
  }

问题是:

1) 如何在第一个版本中实现最后一个版本漂亮的Scala函数风格?

2) 我怎样才能使用 Scala for 呢?我想到了类似下面的东西,但不知道如何。

for {
    i <- 3 until n by 2
    if i * i <= n
  } { ??? }

【问题讨论】:

  • 您的问题不清楚。 “没有任何库”是什么意思?在您的isPrime3 中,您使用了库中的 2 个类和 6 个方法,而在您的 for 理解中,您至少使用了 3 个类和 6 个方法。既然您自己使用库没有问题,那么“没有任何库”究竟是什么意思?
  • 好的,只是没有计算sqrt 是清楚的——我只想对整数进行操作。我改变了问题的主题。

标签: scala functional-programming primes for-comprehension


【解决方案1】:

这是一种在不使用 sqrt 的情况下验证 n 是否为素数直到 sqrt(n) 的方法:

  def isPrime3(n: Int): Boolean = {
    if (n == 2) {
      true
    } else if (n < 2 || n % 2 == 0) {
      false
    } else {
      Stream.from(3, 2).takeWhile(i => i * i < n + 1).forall(i => n % i != 0)
    }
  }

如果你想做到 n/2,这也是一种可能的优化(比sqrt(n) 差),你可以将最后一行替换为:

 (3 to n/2 + 1 by 2).forall(i => n % i != 0)

如果您愿意,也可以制作尾递归版本,类似于以下内容:

  import scala.annotation.tailrec

  def isPrime3(n: Int): Boolean = {
    if (n == 2 || n == 3) {
      true
    } else if (n < 2 || n % 2 == 0) {
      false
    } else {
      isPrime3Rec(n, 3)
    }
  }

  @tailrec
  def isPrime3Rec(n:Int, i: Int): Boolean = {
    (n % i != 0) && ((i * i > n) || isPrime3Rec(n, i + 2))
  }

【讨论】:

  • 我认为大多数人会将范围写为中缀:!(3 to n/2 + 1 by 2).exists(...) - 解密那些 .和 () 在范围内似乎有点不方便。
  • @Suma 谢谢,我改了。它更干净是的
  • n/2 比 sqrt(n) 多很多,你可以重写使用 i * i
  • @BartłomiejSzałach 你当然是对的。我添加了一个新的解决方案,只计算直到 sqrt
  • return 是一种糟糕的风格。我会写if (n % i == 0) false else if (i * i &gt; n) true else isPrime3Rec(n, i + 3)(带换行符)甚至(n % i != 0) &amp;&amp; (i * i &gt; n || isPrime3Rec(n, i + 3))
猜你喜欢
  • 1970-01-01
  • 2016-08-21
  • 2020-04-13
  • 2011-12-28
  • 1970-01-01
  • 2013-03-22
  • 1970-01-01
  • 2015-03-08
  • 2016-02-19
相关资源
最近更新 更多