Enumerate factors of a number directly in ascending order without sorting?

前端 未结 4 1268
野趣味
野趣味 2020-11-27 20:00

Is there an efficient algorithm to enumerate the factors of a number n, in ascending order, without sorting? By “efficient” I mean:

  1. The algorithm a

4条回答
  •  陌清茗
    陌清茗 (楼主)
    2020-11-27 21:06

    In short: Repeatedly pull the next-smallest factor from a heap, then push back every multiple of that factor that is still a factor of n. Use a trick to avoid duplicates arising, so that the heap size never exceeds d. The time complexity is O(kd log d), where k is the number of distinct prime factors.

    The key property that we make use of is that if x and y are both factors of n with y = x*p for some factor p >= 2 -- i.e. if the prime factors of x are a proper submultiset of the prime factors of y -- then x < y. This means that it is always safe to output x before any such y is even inserted into the heap. The heap is effectively used only to compare factors where neither is a submultiset of the other.

    A first attempt: Duplicates slow things down

    It will be helpful to first describe an algorithm that produces the right answer, but also produces many duplicates:

    1. Set prev = NULL.
    2. Insert 1 into a heap H.
    3. Extract the top of heap t from H. If the heap is empty, stop.
    4. If t == prev then goto 3. [EDIT: Fixed]
    5. Output t.
    6. Set prev = t.
    7. For each distinct prime factor p of n:
      • If n % (t*p) == 0 (i.e. if t*p is still a factor of n), push t*p onto H.
    8. Goto 3.

    The only problem with the above algorithm is that it can generate the same factor many times. For example, if n = 30, then the factor 15 will be generated as a child of the factor 5 (by multiplying by the prime factor 3), and also as a child of the factor 3 (by multiplying by 5). One way around this is to notice that any duplicates must be read out in a contiguous block when they reach the top of the heap, so you can simply check whether the top of the heap is equal to the just-extracted value, and to keep extracting and discarding it if so. But a better approach is possible:

    Killing duplicates at the source

    How many ways can a factor x be generated? First consider the case in which x contains no prime factors with multiplicity > 1. In that case, if it contains m distinct prime factors, then there are m-1 "parent" factors that will generate it as a "child" in the previous algorithm -- each of these parents consists of some subset of m-1 of the m prime factors, with the remaining prime factor being the one that gets added to the child. (If x has a prime factor with multiplicity > 1, then there are in fact m parents.) If we had a way of deciding on exactly one of these parents to be the "chosen one" that actually generates x as a child, and this rule resulted in a test that could be applied to each parent at the time that parent is popped off, then we could avoid ever creating any duplicates in the first place.

    We can use the following rule: For any given x, choose the potential parent y that is missing the largest of x's m factors. This makes for a simple rule: A parent y produces a child x if and only if x = y*p for some p greater than or equal to any prime factor already in y. This is easy to test for: Just loop through prime factors in decreasing order, generating children for each, until we hit a prime factor that already divides y. In the previous example, the parent 3 will produce 15, but the parent 5 will not (because 3 < 5) -- so 15 indeed gets produced only once. For n = 30, the complete tree looks like:

           1
          /|\
         2 3 5
        /|  \
       6 10  15
       |
       30
    

    Notice that each factor is generated exactly once.

    The new, duplicate-free algorithm is as follows:

    1. Insert 1 into a heap H.
    2. Extract the top of heap t from H. If the heap is empty, stop.
    3. Output t.
    4. For each distinct prime factor p of n in decreasing order:
      • If n % (t*p) == 0 (i.e. if t*p is still a factor of n), push t*p onto H.
      • If t % p == 0 (i.e. if t already contains p as a factor) then stop.
    5. Goto 2.

提交回复
热议问题