【问题标题】:What is wrong with this prime factorization code in Java?Java中的这个素数分解代码有什么问题?
【发布时间】:2016-08-16 14:36:45
【问题描述】:

我试图制作一种方法来对数字进行素数分解,它可能不是最有效的,但我不明白为什么它不应该工作。

public static ArrayList<Integer> primeFactorize(int num) {
    ArrayList<Integer> primeFactors = new ArrayList<Integer>();

    for (int i = 2; i < Math.sqrt((double) num); i++) {
        if (isPrime(i) && factor(num).contains(i)) {
            primeFactors.add(i);
            num /= i;

            if (isPrime(num)) {
                primeFactors.add(num);
                break;
            }
            i = 2;
        }
    }
    return primeFactors;
}

它调用了我编写的另外两个方法,名为 factor()isPrime(),它们完全符合您的预期(返回因子的 ArrayListtruefalse,具体取决于是否输入分别为素数)。

我通过调试器,num 为 12,它在第一个循环中运行良好,它将 2 添加到 primeFactors。然而,当它再次到达数组顶部时,num 为 6,i 为 2,它退出了循环,就好像i &lt; Math.sqrt((double) num) 返回了false

但这没有意义,因为 6 的平方根略大于 2。我也尝试了 (double) i &lt; Math.sqrt((double) num),但它只是做了同样的事情。

谁能看到我错过了什么?感谢您的任何回复。


编辑:这是我的代码,感谢您的帮助!我确信我可以提高效率,所以我以后可能会这样做,但现在这是完美的。

public static ArrayList<Integer> primeFactorize(int num) {
    ArrayList<Integer> primeFactors = new ArrayList<Integer>();

    int i = 2;
    while (i < Math.sqrt((double) num)) {
        if (isPrime(i) && num % i == 0) {
            primeFactors.add(i);
            num /= i;

            if (isPrime(num)) {
                primeFactors.add(num);
                break;
            }
            i = 2;
        }
        else
            i++;
    }
    return primeFactors;
}

【问题讨论】:

  • sqrt(num),而不是 sqrt(i)。所以当 num=12 时,6 大于 sqrt(num)

标签: java math primes


【解决方案1】:

在您的for 循环中,i++ 部分将在每个循环结束时被调用。因此,在您的代码中,您将i 设置为2。然后,循环结束,并将1 加到i,使其为3。然后进行比较,并且3 大于sqrt(6),所以循环退出。

如果您希望i 在下一次迭代中为 2,您需要将其设置为一个值,以便在 after 递增操作运行时它将为 2,而不是 before;在这种情况下,您应该将其设置为 1。更好的解决方案是更改您的代码结构,这样就没有必要了。 As pointed out by biziclopwhile 循环会让你决定是否递增,并且会避免这个问题。

【讨论】:

  • 我知道它与 i++ 有关,不敢相信我错过了,哈哈,谢谢!
  • 一般建议:如果您在循环体内操作循环变量,请不要使用for 循环。使用while,它会让你的代码更清晰。保留for 用于两点之间的简单循环。
  • 为什么要使用函数factor() ?你只想知道i的当前值是否是num的一个因子,所以(num%i)==0就足够了。
  • 我真的不知道为什么我没有想到这一点,也谢谢你,哈哈
【解决方案2】:

既然您已经接受了答案,我假设您的问题已经解决。我想指出的是,如果有另一种方法,将整数转换为双精度通常是一个坏主意。因此,我想向您展示下面的实现,它不使用浮点运算。另外我认为检查num 是否是素数是个坏主意,因为这会减慢算法的速度。此外,如果num % i == 0 评估为真,i 始终是质数,因此isPrime(i) 检查是多余的,也会减慢您的算法。

List <Integer> primeFactors(int n) {
    List<Integer> factors = new ArrayList<>();
    for (int i = 2; i <= n / i; ++i) {
        while (n % i == 0) {
            factors.add(i);
            n /= i ;
        }
    }
    if (n > 1) {
        factors.add(n);
    }
    return factors ;
}

【讨论】:

  • 非常好的代码,谢谢!听到我如何让我的代码更高效总是很高兴,考虑到作为一名高中生,这是你对 lol 并没有真正了解太多的一件事
  • 不客气,也许你(或我)应该做一个运行时比较;)。顺便说一句,总是欢迎投票:)
  • 我尝试为 5 件事点赞,但我认为我还没有足够的声誉,哈哈
  • 您可以通过在开始时单独处理因子 2 来加速算法,然后每次从 3 将循环更改为第 2 步:for (int i = 3; i &lt;= n / i; i += 2) 这将节省测试任何偶数试验因子,除了 2。
  • 是的,但如果您添加更多检查,您也可以每 6 个数字执行一次。您想添加这么多杂物吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-02
  • 1970-01-01
相关资源
最近更新 更多