【问题标题】:Most Efficient Way to Find All the Factors of a Number?找出一个数的所有因数的最有效方法?
【发布时间】:2017-08-01 18:58:34
【问题描述】:

免责声明:在 SO 上有类似的问题,然而 它们要么都没有解决算法的效率问题,要么是 用不同的语言写成。请参阅this answer 谈话 关于 python 的效率,看看它是否能帮助你回答我的问题。

所以我需要一种有效的方法来找到任何给定数字的所有因数,这种方法可以快速处理非常大的数字。我已经有几次代码迭代可以工作,但需要很长时间来处理超过 6 个字符的数字。

编辑:根据要求,这里是我的一些非有效方法(为清楚起见,省略了错误检查)

真的很乱

    @IBAction func findFactorsButton(_ sender: AnyObject) {
    if let _ = textField.text, !textField.text!.isEmpty {
        counter = 1
        factors = []
        repeat {
            counter += 1
            if Int(textField.text!)! % counter == 0 {
                factors.append(String(counter))
            } else {
                continue
            }
        } while counter != Int(textField.text!)
        factors.removeLast()
        outputLabel.text = factors.joined(separator: ", ")

    } else {
        outputLabel.text = ""
    }
}

不那么凌乱的解决方案(游乐场):

func calculateFactors(n: Int) -> String {
    var result: String = ""
    for i in 1...n {
        guard n % i == 0  else {continue}
        result += i == 1 ? "1" : ", \(i)"
    }
    print(result)
    return result
}

【问题讨论】:

  • 您能否向我们展示这些迭代,按性能最持久的顺序列出?
  • 有效分解单个数字?还是很多?在后一种情况下,您将预先计算素数列表。数字在什么范围内?
  • 这里codereview.stackexchange.com/a/166342/35991 是一个应该比你更快的实现。
  • 求单个数的因数。 不是主要因素。
  • 如何有效地找到所有因素是一个与任何特定编程语言几乎没有关系的算法问题,@SamHarwell 对该问题的回答(由@ColGraff 在此引用)列出了所有解决问题的最佳算法这个问题。当我关闭它时,您的问题中没有 Swift 代码。由于您添加了一些代码,我重新打开了这个问题。

标签: swift algorithm performance


【解决方案1】:

引用的问答What is the most efficient way of finding all the factors of a number in Python? 中的大多数 Python 方法使用以下事实: n 的因子成对出现:如果 i 是一个因子,那么 n/i 是另一个 因素。因此,测试直到平方根的因子就足够了 给定数量的。

这是一个可能的 Swift 实现:

func factors(of n: Int) -> [Int] {
    precondition(n > 0, "n must be positive")
    let sqrtn = Int(Double(n).squareRoot())
    var factors: [Int] = []
    factors.reserveCapacity(2 * sqrtn)
    for i in 1...sqrtn {
        if n % i == 0 {
            factors.append(i)
        }
    }
    var j = factors.count - 1
    if factors[j] * factors[j] == n {
        j -= 1
    }
    while j >= 0 {
        factors.append(n / factors[j])
        j -= 1
    }
    return factors
}

备注:

  • reserveCapacity 用于避免数组重新分配。
  • 首先确定1...sqrtn范围内的所有因子, 然后以相反的顺序附加相应的因子n/i, 以便所有因素都按递增顺序排列。
  • 必须特别注意对于完美的正方形,sqrt(n) 是 未列出两次。

对于最多 8 位小数的数字,最多可试用 9,999 需要分工。例子 (在 1.2 GHz Intel Core m5 MacBook 上,以发布模式编译):

let start = Date()
let f = factors(of: 99999999)
print("Time:", Date().timeIntervalSince(start) * 1000, "ms")
print("Factors:", f)

输出:

时间:0.227034091949463 毫秒 因数:[1、3、9、11、33、73、99、101、137、219、303、411、657、803、909、1111、1233、1507、2409、3333、4521、7227、7373、9999 ,10001,13563,13837,22119,30003,41511,66357,81103,90009,110011,124533,152207,243309,330033,456621,729927,990099,1010101,1369863,3030303,9090909,11111111,33333333,99999999]

【讨论】:

  • 感谢马丁的回答,它比我以前的版本更有效
【解决方案2】:

这一切都取决于你的数字。这是一个很棒的summary

“你的数字有多大?”确定使用的方法:

所以这一切都变成了挑选算法并在 Swift 中实现它们的问题。既然你说你需要带有“6 个字符”的数字,这意味着它们大约是 2^17 左右。所以它是该列表中的选项 2:阿特金筛或波拉德 rho 的修改。

【讨论】:

  • 那么你能和我分享一下修改后的Pollard's Rho算法在swift中的实现吗?
  • 我在 Swift 中没有实现,你必须实现它或找到它。链接给出了通用算法,用 Swift 编码应该比较容易。
猜你喜欢
  • 2011-10-11
  • 2016-03-17
  • 2014-08-01
  • 2015-11-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多