简体   繁体   English

超级丑数

[英]Super Ugly Number

So the problem is:所以问题是:

Write a program to find the nth super ugly number.编写程序找出第n个超级丑数。

Super ugly numbers are positive numbers whose all prime factors are in the given prime list primes of size k.超级丑数是所有质因数都在给定的大小为 k 的质数列表质数中的正数。 For example, [1, 2, 4, 7, 8, 13, 14, 16, 19, 26, 28, 32] is the sequence of the first 12 super ugly numbers given primes = [2, 7, 13, 19] of size 4.例如,[1, 2, 4, 7, 8, 13, 14, 16, 19, 26, 28, 32] 是给定素数 = [2, 7, 13, 19] 的前 12 个超级丑数的序列大小为 4。

So my algorithm basically finds all possible factors using the pattern they follow, pushes them to an array, sorts that array and then returns the nth value in the array.所以我的算法基本上使用它们遵循的模式找到所有可能的因素,将它们推送到一个数组,对该数组进行排序,然后返回数组中的第 n 个值。 It accurately calculates all of them, however, is too slow with high nth values.它准确地计算了所有这些,但是,对于高第 n 个值来说太慢了。

My question is what the proper way to do this is as I'm sure there has to be a more straightforward solution.我的问题是这样做的正确方法是什么,因为我确信必须有一个更直接的解决方案。 I'm mostly curious about the theory behind finding it and if there's some kind of closed formula for this.我很好奇找到它背后的理论,以及是否有某种封闭的公式。

 var nthSuperUglyNumber = function(n, primes) {
     xprimes = primes;
     var uglies = [1];
     uglies = getUglyNumbers(n, primes, uglies);
     // return uglies[n-1];
     return uglies[n - 1];
 };

 //                     3                         4
 //1, 2,3,5, || 4,6,10, 9,15, 25, || 8,12,20,18,30,50, 27,45,75, 125 ||
 //   3,2,1     6,3,1,               10,4,1
 //              1            1              1
 //1, 2,3 || 4,6, 9, || 8,12,18, 27 || 16,24,36,54, 81
 //   2,1    3,1        4,1            5,1
 //
 //1, 2,3,5,7 || 4,6,10,14 9,15,21 25,35, 49 ||
 //   4,3,2,1 || 10,6,3,1

 var getUglyNumbers = function(n, primes, uglies) {
     if (n == 1) {
         return uglies;
     }
     var incrFactor = [];

     var j = 0;
     // Initial factor and uglies setup
     for (; j < primes.length; j += 1) {
         incrFactor[j] = primes.length - j;
         uglies.push(primes[j]);
     }

     //recrusive algo
     uglies = calcUglies(n, uglies, incrFactor);
     uglies.sort(function(a, b) {
     return a - b;
     });
     return uglies;
 };

 var calcUglies = function(n, uglies, incrFactor) {
     if (uglies.length >= 5 * n) return uglies;
     var currlength = uglies.length;
     var j = 0;
     for (j = 0; j < xprimes.length; j += 1) {
         var i = 0;
         var start = currlength - incrFactor[j];
         for (i = start; i < currlength; i += 1) {
             uglies.push(xprimes[j] * uglies[i]);
         }
     }
     // Upgrades the factors to level 2
     for (j = 1; j < xprimes.length; j += 1) {
         incrFactor[xprimes.length - 1 - j] = incrFactor[xprimes.length - j] + incrFactor[xprimes.length - 1 - j];
     }

     return calcUglies(n, uglies, incrFactor);
 };
public static ArrayList<Integer> superUgly(int[] primes,int size)
{
    Arrays.sort(primes);
    int pLen = primes.length;

    ArrayList<Integer> ans = new ArrayList<>();
    ans.add(1);

    PriorityQueue<pair> priorityQueue = new PriorityQueue<>(Comparator.comparingInt(p -> p.value));
    HashSet<Integer> hashSet = new HashSet<>();

    int next_ugly_number;
    int[] indices = new int[pLen];

    for(int i=0;i<pLen;i++) {
        hashSet.add(primes[i]);
        priorityQueue.add(new pair(i,primes[i]));
    }

    while(ans.size()!=size+1)
    {
        pair pair = priorityQueue.poll();
        next_ugly_number = pair.value;
        ans.add(next_ugly_number);
        indices[pair.index]+=1;

        int temp = ans.get(indices[pair.index])*primes[pair.index];
        if (!hashSet.contains(temp))
        {
            priorityQueue.add(new pair(pair.index,temp));
            hashSet.add(temp);
        }
        else {
            while(hashSet.contains(temp))
            {
                indices[pair.index]+=1;
                 temp = ans.get(indices[pair.index])*primes[pair.index];

            }
            priorityQueue.add(new pair(pair.index,temp));
            hashSet.add(temp);

        }

    }

    ans.remove(0);
    return ans;
}

Pair class is对类是

class pair
{
    int index,value;
    public pair(int i,int v)
    {
        index = i;
        value = v;
    }
}

It returns a list of ugly numbers of size 'size'.它返回一个大小为“大小”的丑陋数字列表。
I am using priority queue to find minimum for every loop and also a hashset to avoid duplicate entries in priorityQueue.我正在使用优先级队列来为每个循环找到最小值,并使用一个哈希集来避免优先级队列中的重复条目。
So its time complexity is O(n log(k)) where n is size and k is primes array size.所以它的时间复杂度是O(n log(k)) ,其中n是大小, k是素数数组大小。

This is the most optimal solution I could write using Dynamic Programming in Python.这是我可以使用 Python 中的动态编程编写的最佳解决方案。

Time complexity: O(n * k)时间复杂度:O(n * k)

Space Complexity: O(n)空间复杂度:O(n)

from typing import List


def super_ugly_numbers(n: int, primes: List[int]) -> int:
    # get nth super ugly number
    ugly_nums = [0] * n
    ugly_nums[0] = 1
    length = len(primes)
    mul_indices = [0] * length
    multipliers = primes[:]

    for index in range(1, n):
        ugly_nums[index] = min(multipliers)

        for in_index in range(length):
            if ugly_nums[index] == multipliers[in_index]:
                mul_indices[in_index] += 1
                multipliers[in_index] = ugly_nums[mul_indices[in_index]] * primes[in_index]

    return ugly_nums[n-1]

This algorithm performs better for large n .该算法对于较大的n表现更好。

primes := {2, 7, 13, 19}
set list := {1}
for i in 1..n-1:
  set k = list[0]
  for p in primes:
    insert p*k into list unless p*k is in list
  remove list[0] from list
return list[0]

If inserting in order is hard, you can just insert the elements into the list at the end and sort the list just after removing list[0].如果按顺序插入很困难,您可以将元素插入到列表的最后并在删除列表 [0] 后对列表进行排序。

import java.util.*;
import java.lang.*;
import java.io.*;
public  class Solution{

    public static void main(String[] args) {
        Scanner fi = new Scanner(System.in);
        int n=fi.nextInt();
        int i;
        int primes[] ={2,3,5};
        HashSet<Integer> hm=new HashSet<>();
        PriorityQueue<Integer> pq=new PriorityQueue<>();
        TreeSet<Integer> tr=new TreeSet<>();
        tr.add(1);
        pq.add(1);
        hm.add(1);

        for (i=0;i<primes.length;i++){
            tr.add(primes[i]);
            pq.add(primes[i]);
            hm.add(primes[i]);
        }
        int size=tr.size();
        while (size < n){
            int curr=pq.poll();
            for (i=0;i<primes.length;i++){
                if (!hm.contains(curr*primes[i])) {
                    tr.add(curr * primes[i]);
                    hm.add(curr*primes[i]);
                    pq.add(curr*primes[i]);
                    size++;
                }
            }

        }
        System.out.println(tr);
    }
}

This might as Help as TreeSet maintains element in sorted order so need to worry about index.这可能有助于 TreeSet 按排序顺序维护元素,因此需要担心索引。

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

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