简体   繁体   English

项目Euler#3永远用Java

[英]Project Euler #3 takes forever in Java

Problem #3 on Project Euler is: Project Euler上的问题#3是:

The prime factors of 13195 are 5, 7, 13 and 29. 13195的主要因素是5,7,13和29。

What is the largest prime factor of the number 600851475143? 600851475143的最大主要因素是什么?

My solution takes forever. 我的解决方案永远。 I think I got the right implementation; 我认为我得到了正确的实施; however, when testing with the big number, I have not being able to see the results. 但是,当用大数字进行测试时,我无法看到结果。 It runs forever. 它永远运行。 I wonder if there's something wrong with my algorithm: 我想知道我的算法是否有问题:

public class LargestPrimeFactor3 {

    public static void main(String[] args) {
        long start, end, totalTime;
        long num = 600851475143L;
        long pFactor = 0;

        start = System.currentTimeMillis();

        for(int i = 2; i < num; i++) {
            if(isPrime(i)) {                
                if(num % i == 0) {
                    pFactor = i;                        
                }
            }
        }

        end = System.currentTimeMillis();
        totalTime = end - start;
        System.out.println(pFactor + " Time: "+totalTime);
    }

    static boolean isPrime(long n) {

        for(int i = 2; i < n; i++) {
            if(n % i == 0) {
                return false;
            }
        }        
        return true;
    }     
}

Although not in Java, I think you can probably make out the following. 虽然不是Java,但我认为你可能会发现以下内容。 Basically, cutting down on the iterations by only testing odd divisors and up to the square root of a number is needed. 基本上,需要通过仅测试奇数除数和直到数字的平方根来减少迭代。 Here is a brute force approach that gives an instant result in C#. 这是一种蛮力方法,可以在C#中实现即时结果。

static bool OddIsPrime (long oddvalue)  // test an odd >= 3 
{
    // Only test odd divisors.
    for (long i = 3; i <= Math.Sqrt(oddvalue); i += 2)
    {
        if (value % i == 0)
            return false;
    }
    return true;
}

static void Main(string[] args)
{
    long max = 600851475143;   // an odd value
    long maxFactor = 0;

    // Only test odd divisors of MAX. Limit search to Square Root of MAX.
    for (long i = 3; i <= Math.Sqrt(max); i += 2)
    {
        if (max % i == 0)
        {
            if (OddIsPrime(i))  // i is odd
            {
                maxFactor = i;
            }
        }
    }
    Console.WriteLine(maxFactor.ToString());
    Console.ReadLine();
}

You should divide out each factor as it is found. 如发现您应该划分的每个因素。 Then there is no need to test them for primality, when we enumerate the possible divisors in ascending order (any thus found divisor can't be compound, its factors will be divided out already). 然后,当我们按升序计算可能的除数时,没有必要测试它们的素数(任何因此找到的除数不能是复数,它的因子将被分开)。 Your code then becomes: 然后你的代码变成:

class LargestPrimeFactor4 {

    public static void main(String[] args) {
        long start, end, totalTime;
        long num = 600851475143L;   // odd value is not divided by any even
        long pFactor = 1L;

        start = System.currentTimeMillis();

        for(long i = 3L; i <= num / i; ) 
        {
            if( num % i == 0 ) {
                pFactor = i;
                num = num / i;
            }
            else {
                i += 2;
            }
        }
        if( pFactor < num ) { pFactor = num; }

        end = System.currentTimeMillis();
        totalTime = end - start;
        System.out.println( pFactor + " Time: " + totalTime);
    }
}
public HashSet<Integer> distinctPrimeFactors(int n) //insane fast prime factor generator
{
    HashSet<Integer> factors = new HashSet<Integer>();
    int lastres = n;
    if (n==1)
    {
        factors.add(1);
        return factors;
    }
    while (true)
    {
        if (lastres==1)
            break;
        int c = 2;
        while (true)
        {
            if (lastres%c==0)
                break;
            c++;
        }
        factors.add(c);
        lastres/=c;
    }
    return factors;
}

If you want to generate distinct prime factors for a number quickly use this method which makes the number smaller on each iteration. 如果要快速生成数字的不同素因子,请使用此方法,使每次迭代的数字变小。 You can change int to long and it should work for you. 您可以将int更改为long,它应该适合您。

Here's pseudocode for integer factorization by trial division: 这是通过试验分区进行整数分解的伪代码:

define factors(n)

    z = 2

    while (z * z <= n)

        if (n % z == 0)
            output z
            n /= z

        else
            z++

    output n

The easiest way to understand this is by an example. 理解这一点的最简单方法是通过一个例子。 Consider the factorization of n = 13195. Initially z = 2, but dividing 13195 by 2 leaves a remainder of 1, so the else clause sets z = 3 and we loop. 考虑n = 13195的因子分解。最初z = 2,但是将13195除以2会得到1的余数,所以else子句设置z = 3并且我们循环。 Now n is not divisible by 3, or by 4, but when z = 5 the remainder when dividing 13195 by 5 is zero, so output 5 and divide 13195 by 5 so n = 2639 and z = 5 is unchanged. 现在n不能被3或4整除,但是当z = 5时,将13195除以5时的余数为零,因此输出5并将13195除以5使得n = 2639并且z = 5不变。 Now the new n = 2639 is not divisible by 5 or 6, but is divisible by 7, so output 7 and set n = 2639 / 7 = 377. Now we continue with z = 7, and that leaves a remainder, as does division by 8, and 9, and 10, and 11, and 12, but 377 / 13 = 29 with no remainder, so output 13 and set n = 29. At this point z = 13, and z * z = 169, which is larger than 29, so 29 is prime and is the final factor of 13195, so output 29. The complete factorization is 5 * 7 * 13 * 29 = 13195. 现在新的n = 2639不能被5或6整除,但是可以被7整除,所以输出7并设置n = 2639/7 = 377.现在我们继续z = 7,剩下的就像是除法一样通过8,9和10,11和12,但377/13 = 29没有余数,所以输出13并设置n = 29.此时z = 13,z * z = 169,这是大于29,所以29是素数并且是13195的最终因子,因此输出29.完全因子分解为5 * 7 * 13 * 29 = 13195。

There are better algorithms for factoring integers using trial division, and even more powerful algorithms for factoring integers that use techniques other than trial division, but the algorithm shown above will get you started, and is sufficient for Project Euler #3. 有更好的算法可以使用试验除法对整数进行因子分解,甚至更强大的算法可以使用除试验除法之外的技术对整数进行因子分解,但上面显示的算法可以帮助您入门,并且足以满足Project Euler#3的要求。 When you're ready for more, look here . 当你准备好了更多时,请看这里

Two things to improve performance: 提高性能的两件事:

static boolean isPrime(long n)
{
    for(int i = 2; i <= sqrt(n); i++)  // if n = a * b, then either a or b must be <= sqrt(n).
    {
        if(n % i == 0)
        {
            return false;
        }
    }        
    return true;
}  

now for the main loop 现在为主循环

for(int i = num; i > 1; i--) // your interested in the biggest, so search from high to low until you have a match
{
    if(num % i == 0 && isPrime(i)) // check for num % i == 0 is faster, so do this first
    {
        pFactor = i;
        break; // break if you have a factor, since you've searched from the top
    }
}

There are still things one can improve here, but that's for you to find out. 在这里仍然有一些可以改进的东西,但那是你找到的。 Think of modifying num . 想想修改num Have fun with project Euler :) 与项目欧拉玩得开心:)

You could just prime factorize the number and then the largest prime factor would be the answer: 你可以只是对数字进行分解,然后最大的素数就是答案:

import java.util.ArrayList;
import java.util.Collections;

public class PrimeFactorization {

    /* returns true if parameter n is a prime number, 
         false if composite or neither */
    public static boolean isPrime(long n) {
        if (n < 2) return false;
        else if (n == 2) return true;
        for (int i = 2; i < Math.pow(n, 0.5) + 1; i++)
            if (n % i == 0)
                return false;
        return true;
    }

    /* returns smallest factor of parameter n */
    public static long findSmallestFactor(long n) {
        int factor = 2; // start at lowest possible factor
        while (n % factor != 0) { // go until factor is a factor
            factor++; // test the next factor
        }
        return factor;
    }

    /* reduces the parameter n into a product of only prime numbers
       and returns a list of those prime number factors */
    public static ArrayList<Long> primeFactorization(long n) {

        ArrayList<Long> primes = new ArrayList<Long>();
          // list of prime factors in the prime factorization
        long largestFactor = n / findSmallestFactor(n);    

        long i = 2;
        while (i <= largestFactor) { 
          // for all possible prime factors 
          // (2 - largest factor of the number being reduced)

            if (isPrime(i) && n % i == 0) { 
                // if this value is prime and the number is divisible by it

                primes.add(i); // add that prime factor to the list
                n /= i; // divide out that prime factor from the number 
                        // to start reducing the new number
                largestFactor /= i; // divide out that prime factor 
                       // from the largest factor to get the largest 
                       // factor of the new number
                i = 2; // reset the prime factor test
            } else {
                i++; // increment the factor test
            }
        }

        primes.add(n); // add the last prime number that could not be factored
        Collections.sort(primes);
        return primes;
    }
}

And then call it like this: 然后像这样调用它:

ArrayList<Long> primes = PrimeFactorization.primeFactorization(600851475143L);
System.out.println(primes.get(primes.size() - 1));

The entire thing takes only a few milliseconds. 整个过程只需几毫秒。

It's not the perfect solution, but it will work for 600851475143. 这不是完美的解决方案,但它适用于600851475143。

public static void main(String[] args) {
    long number= 600851475143L;
    int rootOfNumber = (int)Math.sqrt(number)+10;
    for(int i = rootOfNumber; i > 2; i--) {
        if(number % i == 0) {
            if(psudoprime(i)) {
                System.out.println(i);
                break;
            }
        }
    }

}

public static boolean psudoprime(int num) {
    for(int i = 2; i < 100; i++) {
        if(num % i == 0) {
            return false;
        }
    }
    return true;
}
public class LargestPrimeFactor {
    static boolean isPrime(long n){
        for(long i=2;i<=n/2;i++){
            if(n%i==0){
                return false;                                               
            }
        }
        return true;    
    }

    static long LargestPrimeFact(long n){
        long largestPrime=0;
        for(long i=2;i<Math.sqrt(n)/2;i++){
            if(n%i==0){
                if(isPrime(i)){
                    largestPrime=i;
                }
                }                                       
            }
        return largestPrime;
    }
    public static void main(String args[]) {
        System.out.println (LargestPrimeFact(600851475143L));
    }
}

Source: http://crispylogs.com/project-euler-problem-3-solution/ 资料来源: http//crispylogs.com/project-euler-problem-3-solution/

This one works perfectly!! 这一个完美!

public class Puzzle3 {
public static void main(String ar[])
{
    Long i=new Long("1");
    Long p=new Long("600851475143");
    Long f=new Long("1");
    while(p>=i)
    {
        if(p%i==0)
        {
            f=i;
            p=p/i;
            int x=1;
            i=(long)x;
        }
        i=i+2;
    }
    System.out.println(f);
}

} }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM