简体   繁体   中英

Print all unique prime factors of a number in ascending order

I'm a beginner and completely confused, I need to display all the prime divisors of a number, but in the first code the calculation takes long time, and in the second code, if I enter the number 2, then java prints 1 and 2. but I just need 2.

Example:

input 360
output 2 3 5

input 2
output 2

input 999999797
output 999999797

If I enter 999999797 then " time limit " what's my mistakes?

for (d = 2; x > 1; d++) {
    if (x % d == 0) {
        x = x / d;
        for (int i = 0; x % d == 0; i++) {
            x = x / d;
        }
        System.out.println(d);
    }
}

AND

 for (d = 2; x % d == 0; d++) {
     for (int i = 0; x % d == 0; i++) {
        x = x / d;
     }
     System.out.println(d);
 }
 System.out.println(x);

Cleaned up the code for the first snippet (which actually is nice) would be:

    int d = 2;
    int step = 1;
    while (x > 1) {
        if (x % d == 0) {
            System.out.println(d);
            x /= d;
            while (x % d == 0) {
                x /= d;
            }
        }
        d += step;
        step = 2;
    }

I added a small optimisation to test only 2, 3, 5, 7, 9 and so on, to demonstrate that many divisors are not needed to be tested. Half the candidates.

Generalized to skip 2, 3, 5:

For a number modulo 2 * 3 * 5:

// Unneeded code:
boolean[] dividable = new int[2*3*5]; // non-candidates to be skipped.
for (int i = 0; i < dividable.length; ++i) {
    dividable[i] = i % 2 == 0 || i % 3 == 0 || i % 5 == 0;
}
// cycle length: 2*3*5 == 30.
// result: tfttt ttftt tftft ttftf tttft ttttf
// steps:   2      7   11 13  17 19  23     29 (8 from 30 candidates, a fourth)

Then the code could be optimized (more ugly though) further:

final int cycleLength = 2*3*5;
final int[] initialSteps = {  2, 3, 5, 7, 11, 13, 17, 19, 23, 29};
final int[] nextSteps =    {1,         7, 11, 13, 17, 19, 23, 29};
int[] steps = initialSteps;
for (int b = 0; x > 1; b += cycleLength) {
    for (int i = 0; x > 1 && i < steps.length; ++i) {
        int d = b + steps[i];
        while (x > 1) {
            if (x % d == 0) {
                System.out.println(d);
                x /= d;
                while (x % d == 0) {
                    x /= d;
                }
            }
        }
    }
    steps = nextSteps;
}

Slightly less than five times faster. (Untested code.)

For those with an interest in math: notice how the steps are ofcourse primes themselves, and the condition for the initialSteps should contain (i % P == 0 && i / P == 1) .


Without arrays, using bits instead

As one of the requirements seems to be to avoid arrays (though here they are of fixed limited length), one can use bits. For 30 bits an int suffices.

final int cycleLength = 2*3*5;
final int common = 1<<7 | 1<<11 | 1<<13 | 1<<17
       | 1<<19 | 1<<23 | 1<<29;
final int initialSteps = 1<<2 | 1<<3 | 1<<5 | common;
final int nextSteps =   1<<1 | common;
long steps = initialSteps;
for (int b = 0; x > 1; b += cycleLength) {
    for (int i = 0, int mask = 1; x > 1 && i < cycleLength; ++i, mask <<= 1) {
        if ((steps & mask) != 0) {
            int d = b + i;
            while (x > 1) {
                if (x % d == 0) {
                    System.out.println(d);
                    x /= d;
                    while (x % d == 0) {
                        x /= d;
                    }
                }
            }
        }
    }
    steps = nextSteps;
}

Be warned that this is even more ugly, and I am far from sure the code is correct.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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