查找数字所有因素的最有效方法?

时间:2017-08-01 18:58:35

标签: swift algorithm performance

  

免责声明:在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
}

2 个答案:

答案 0 :(得分:5)

引用的Q& A 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)

输出:

Time: 0.227034091949463 ms
Factors: [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]

答案 1 :(得分:2)

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

  

"你的数字有多大?"确定要使用的方法:

     

所以这一切都变成了选择算法并在Swift中实现它们的问题。因为你说你需要带有#34; 6个字符的数字"这意味着它们大概在2 ^ 17左右。所以它在该列表中的选项2:Atkin的Sieve或Pollard的rho的修改。