【问题标题】:Prime factorization with return being a string返回为字符串的素数分解
【发布时间】:2021-08-30 17:49:00
【问题描述】:

我正在尝试解决以下编码挑战:

给定一个正数n > 1,求n 的素因子分解。结果将是一个格式如下的字符串:

"(p1xxn1)(p2xxn2)...(pkxxnk)"

p(i) 按递增顺序排列,如果 n(i)1,则 n(i) 为空。

示例:n = 86240 应返回 "(2xx5)(5)(7xx2)(11)"

我相信我已经知道如何找到一个数字的主要因素......我的问题是我不知道如何将它们转换为问题所需的形式(即 p(i) 的字符串是递增的顺序)。我试图将包含素数因子的整数数组转换为某种包含因子 p 和 n 的元组数组,但我已经苦苦挣扎了几个小时。

这是我目前所拥有的:

func factors(_ number: Int) -> String {
    var changedNumber = number
    var numberArr = [Int]()

    while changedNumber >= 2 {
        for i in 2...changedNumber {
            if changedNumber % i == 0 {
                numberArr.append(i)
                changedNumber /= i
                break
            }
        }
    }
}

任何见解或资源将不胜感激。

【问题讨论】:

    标签: swift string algorithm prime-factoring


    【解决方案1】:

    func factors(_ number: Int) -> String

    我认为直接返回String 是错误的。它违反了职责分离,并使其难以重用。

    想象一下在代码库中的其他地方使用这个函数,可能有一个函数试图将这个字符串结果解析回一个数组,以便以其他方式使用它。这听起来可能很荒谬,但我们在这里遇到的很多问题都是关于人们试图构建系统以接受来自其他系统的愚蠢输入,而他们应该改变它们!

    以下是我的建议:

    func primeFactorization(of value: Int) -> (factor: Int, exponent: Int) {
        ...
    }
    
    func format(_ primeFactors: [(factor: Int, exponent: Int)]) -> String {
        return primeFactors
            .map { $0.exponent == 1 ? "(\($0.factor))" : "(\($0.factor)xx\($0.exponent))" }
            .joined()
    
    }
    

    所以你可以这样做:

    let factorization = primeFactorization(of: 86240)
    // Which results in: [
    //     (factor: 2, exponent: 5),
    //     (factor: 2, exponent: 1),
    //     (factor: 7, exponent: 2),
    //     (factor: 11, exponent: 1),
    // ]
    
    // Which you can then format as this one question wants:
    format(factorization) // => "(2xx5)(5)(7xx2)(11)"
    

    另外,您可以将第一个函数泛化为BinaryInteger 上的扩展,这样您就可以编写类似86240.primeFactorization() 的内容。

    【讨论】:

    • 哦,这就是(2xx5)(5)(7xx2)(11) 的意思。这个问题现在更有意义了。
    • .join(separator: "") 应该是 .joined(separator: "") 或者只是 .joined()
    • 哇,非常感谢亚历山大的帮助!
    【解决方案2】:

    只需让你的函数对数字进行分组,然后在创建字符串时使用每个子集合计数:

    func factors(_ number: Int) -> String {
        var changedNumber = number
        var numberArr: [[Int]] = []
        while changedNumber >= 2 {
            for i in 2...changedNumber {
                if changedNumber.isMultiple(of: i) {
                    if numberArr.last?.last == i {
                        numberArr[numberArr.count-1].append(i)
                    } else {
                        numberArr.append([i])
                    }
                    changedNumber /= i
                    break
                }
            }
        }
        return numberArr.reduce(into: "") {
            if let last = $1.last {
                if $1.count == 1 {
                   $0 += "(" + String(last) + ")"
                } else {
                   $0 += "(" + String(last) + "xx\($1.count))"
                }
            }
        }
    }
    

    print(factors(86240))   // (2xx5)(5)(7xx2)(11)
    

    【讨论】:

    • 你应该使用 reduce(into:) 来防止字符串上的牛复制,虽然我认为这更适合 map+join
    • @Alexander 考虑到字符串的大小应该没有任何区别。
    • 是的。虽然我个人认为 map+join 模式更具可读性。
    【解决方案3】:

    有很多方法可以处理这个问题。这是一个,在我的脑海中:

    编写一个具有以下功能的 Int 扩展

    func isPrime() -> Bool
    
    func nextPrime() -> Int.
    

    首先检查输入数字 n 是否为素数。如果是,则将结果返回为“(nxxx1)”,您就完成了。

    定义一个结构体primeFactor:

    struct PrimeFactor {
       let value: Int
       var count: Int
    }
    

    创建一个 PrimeFactors 数组。

    func primeFactorsString(of value: String) -> String {
        var primeFactors = [PrimeFactor]()
        var currentPrime = 1
        var remainder = value
        guard !value.isPrime() else { return "(\(value)xx1)" }
        while remainder > 1 {
           currentPrime = currentPrime.nextPrime()
           if remainder % currentPrime == 0 {
              let newPrimeFactor = PrimeFactor(value: currentPrime, count: 1)
              remainder /= currentPrime
              while remainder % currentPrime == 0 {
                  newPrimeFactor.count = newPrimeFactor.count + 1
                  remainder /= currentPrime
              }
              primeFactors.append(newPrimeFactor)
           }
        }
        // Now loop through your array of primeFactors and build your output string.
        return primeFactors.map { "(\($0.value)xx\($0.count))".joined()
    

    【讨论】:

    • 非常感谢邓肯!
    • 请注意,您应该提出以下问题:可以传递给此函数的最大值是多少:然后您应该预先构建一个从 2 到 ≤sqrt(largest) 的素数数组并使用这些预先计算素数来编写您的 isPrime () 和 nextPrime() 函数。这将使您的算法更加高效。
    • 个人喜好,但我建议将元组用于像这样的纯数据、无方法、短暂的值。
    • @Alexander 公平点。使用具有命名值的元组,您可以获得与结构中的命名属性相同的好处。
    猜你喜欢
    • 2015-01-27
    • 2019-06-13
    • 1970-01-01
    • 2020-09-05
    • 1970-01-01
    • 2013-10-26
    • 1970-01-01
    • 1970-01-01
    • 2019-12-27
    相关资源
    最近更新 更多