[英]Super Ugly Number
所以問題是:
編寫程序找出第n個超級丑數。
超級丑數是所有質因數都在給定的大小為 k 的質數列表質數中的正數。 例如,[1, 2, 4, 7, 8, 13, 14, 16, 19, 26, 28, 32] 是給定素數 = [2, 7, 13, 19] 的前 12 個超級丑數的序列大小為 4。
所以我的算法基本上使用它們遵循的模式找到所有可能的因素,將它們推送到一個數組,對該數組進行排序,然后返回數組中的第 n 個值。 它准確地計算了所有這些,但是,對於高第 n 個值來說太慢了。
我的問題是這樣做的正確方法是什么,因為我確信必須有一個更直接的解決方案。 我很好奇找到它背后的理論,以及是否有某種封閉的公式。
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;
}
對類是
class pair
{
int index,value;
public pair(int i,int v)
{
index = i;
value = v;
}
}
它返回一個大小為“大小”的丑陋數字列表。
我正在使用優先級隊列來為每個循環找到最小值,並使用一個哈希集來避免優先級隊列中的重復條目。
所以它的時間復雜度是O(n log(k))
,其中n
是大小, k
是素數數組大小。
這是我可以使用 Python 中的動態編程編寫的最佳解決方案。
時間復雜度:O(n * k)
空間復雜度: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]
該算法對於較大的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]
如果按順序插入很困難,您可以將元素插入到列表的最后並在刪除列表 [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);
}
}
這可能有助於 TreeSet 按排序順序維護元素,因此需要擔心索引。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.