超级丑数的思路探讨与源码
超级丑数的题目如下图,该题属于数组类和数学类型的题目,主要考察对于数组搜索方法的使用和数学方法的理解。本文的题目作者想到2种方法,分别是优先队列方法和动态规划方法,其中优先队列方法使用Java进行编写,而动态规划方法使用Python进行编写,当然这可能不是最优的解法,还希望各位大佬给出更快的算法。
本人认为该题目可以使用优先队列方法的思路进行解决,首先初始化一个优先队列,并将队列元素添加最小丑数1,然后开始遍历循环,如果循环完毕就返回结果,否则就开始搜索数组,取出其中最小值,然后将最小值所对应的丑数进行插入队列的操作,最终直到循环结束并返回结果。那么按照这个思路我们的Java代码如下:
#喷火龙与水箭龟
class Solution {
public int nthSuperUglyNumber(int n, int[] primes) {
PriorityQueue<Integer> queueList = new PriorityQueue<>();
queueList.add(1);
while (n-- > 0) {
int pollNum = queueList.poll();
if (n == 0){
return pollNum;
}
for (int jr:primes) {
if (jr <= Integer.MAX_VALUE / pollNum){
queueList.add(jr*pollNum);
}
if (pollNum % jr == 0){
break;
}
}
}
return -1;
}
}
显然,我们看到优先队列方法的效果还可以,同时还可以使用动态规划的方法解决。首先计算数组的长度,并初始化动态规划数组,动态规划的数组元素是代表第n+1个丑数,再把动态规划数组的第一个元素设置为1;再初始化一个代表每个质因子现在与哪个丑数相乘的数组。然后开始遍历循环数组,如果当前质因子乘它的丑数小于当前的丑数,就更新当前丑数并更新变化坐标,如果相等就直接进行变化操作。以此循环,直到最终结束并返回结果。所以按照这个思路就可以解决,下面是Python代码:
#喷火龙与水箭龟
class Solution:
def nthSuperUglyNumber(self, n: int, primes: List[int]) -> int:
primesLen = len(primes)
dpArr = [inf] * n
dpArr[0] = 1
indArr = [0] * primesLen
for ir in range(1, n):
changeFlag = 0
for jr in range(primesLen):
if(primes[jr] * dpArr[indArr[jr]] < dpArr[ir]):
changeFlag = jr
dpArr[ir] = primes[jr] * dpArr[indArr[jr]]
elif(primes[jr] * dpArr[indArr[jr]] == dpArr[ir]):
indArr[jr] = indArr[jr] + 1
indArr[changeFlag] = indArr[changeFlag] + 1
return dpArr[-1]
从结果来说Java版本的优先队列的效率还可以,而Python版本的动态规划方法的速度也不错,但应该是有更多的方法可以进一步提速的,希望朋友们能够多多指教,非常感谢。