题目:
超级丑数 是一个正整数,并满足其所有质因数都出现在质数数组 primes 中。
给你一个整数 n 和一个整数数组 primes ,返回第 n 个 超级丑数 。
题目数据保证第 n 个 超级丑数 在 32-bit 带符号整数范围内。
解答:
方法一:python
class Solution:
def nthSuperUglyNumber(self, n: int, primes: List[int]) -> int:
m=len(primes)
#pointers:与primes相对应,代表当前prime的几倍待添加进结果数组,倍数源自超级丑数序列(即dp数组),pointers仅记录倍数的索引,具体倍数需访问dp数列
#pointers的元素初始皆为0,即皆指向超级丑数序列(dp数列)的第一个数
pointers=[0]*m
#dp[i]:表示第i个超级丑数
dp=[0]*n
dp[0]=1
for i in range(1,n):
dp[i]=min([dp[pointers[j]]*primes[j] for j in range(m)])
#dp[i]的产生可能同时源自两个丑数,比如:14=2*7=7*2
#dp[i]最终选取了某个或某些prime的倍数,则这些prime对应的倍数应该加1
for j in range(m):
if dp[pointers[j]]*primes[j]==dp[i]:
pointers[j]+=1
#print(dp)
return dp[n-1]
方法2:试图对方法1进行优化,但依旧超时
class Solution:
def nthSuperUglyNumber(self, n: int, primes: List[int]) -> int:
m=len(primes)
#pointers:与primes相对应,代表当前prime的几倍待添加进结果数组,倍数源自超级丑数序列(即dp数组)
#pointers的元素初始皆为0,即皆指向超级丑数序列(dp数列)的第一个数
pointers=[0]*m
#dp[i]:表示第i个超级丑数
dp=[float('inf')]*n
dp[0]=1
for i in range(1,n):
for j in range(m):
tmp=dp[pointers[j]]*primes[j]
if tmp==dp[i]:
source.append(j)
if tmp<dp[i]:
source=[j]
dp[i]=tmp
#dp[i]的产生可能同时源自两个丑数,比如:14=2*7=7*2
#dp[i]最终选取了某个或某些prime的倍数,则这些prime对应的倍数应该加1
for idx in source:
pointers[idx]+=1
return dp[n-1]
方法3:同样的思路用Java提交,通过未超时
class Solution {
public int nthSuperUglyNumber(int n, int[] primes) {
int[] dp = new int[n + 1];
dp[1] = 1;
int m = primes.length;
int[] pointers = new int[m];
Arrays.fill(pointers, 1);
for (int i = 2; i <= n; i++) {
int[] nums = new int[m];
int minNum = Integer.MAX_VALUE;
for (int j = 0; j < m; j++) {
nums[j] = dp[pointers[j]] * primes[j];
minNum = Math.min(minNum, nums[j]);
}
dp[i] = minNum;
for (int j = 0; j < m; j++) {
if (minNum == nums[j]) {
pointers[j]++;
}
}
}
return dp[n];
}
}